trilogy 2.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of trilogy might be problematic. Click here for more details.

Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +74 -0
  4. data/Rakefile +18 -0
  5. data/ext/trilogy-ruby/cast.c +272 -0
  6. data/ext/trilogy-ruby/cext.c +933 -0
  7. data/ext/trilogy-ruby/extconf.rb +16 -0
  8. data/ext/trilogy-ruby/inc/trilogy/blocking.h +163 -0
  9. data/ext/trilogy-ruby/inc/trilogy/buffer.h +64 -0
  10. data/ext/trilogy-ruby/inc/trilogy/builder.h +161 -0
  11. data/ext/trilogy-ruby/inc/trilogy/charset.h +277 -0
  12. data/ext/trilogy-ruby/inc/trilogy/client.h +546 -0
  13. data/ext/trilogy-ruby/inc/trilogy/error.h +43 -0
  14. data/ext/trilogy-ruby/inc/trilogy/packet_parser.h +34 -0
  15. data/ext/trilogy-ruby/inc/trilogy/protocol.h +756 -0
  16. data/ext/trilogy-ruby/inc/trilogy/reader.h +212 -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 +241 -0
  22. data/ext/trilogy-ruby/src/buffer.c +60 -0
  23. data/ext/trilogy-ruby/src/builder.c +198 -0
  24. data/ext/trilogy-ruby/src/charset.c +212 -0
  25. data/ext/trilogy-ruby/src/client.c +728 -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 +676 -0
  29. data/ext/trilogy-ruby/src/reader.c +244 -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 +36 -0
  34. data/lib/trilogy/version.rb +3 -0
  35. data/lib/trilogy.rb +61 -0
  36. data/trilogy.gemspec +27 -0
  37. metadata +106 -0
@@ -0,0 +1,546 @@
1
+ #ifndef TRILOGY_CLIENT_H
2
+ #define TRILOGY_CLIENT_H
3
+
4
+ #include <sys/socket.h>
5
+ #include <sys/types.h>
6
+ #include <unistd.h>
7
+
8
+ #include "trilogy/buffer.h"
9
+ #include "trilogy/packet_parser.h"
10
+ #include "trilogy/protocol.h"
11
+ #include "trilogy/socket.h"
12
+
13
+ /* Trilogy Non-blocking Client API
14
+ *
15
+ * This API is designed for allowing the caller to deal with I/O themselves.
16
+ * The API is split into `_send` and `_recv` calls. Allowing the caller to wait
17
+ * on writeability before calling a `_send` function, and waiting for
18
+ * readability before `_recv` calls. This can especially be useful for
19
+ * applications that live inside of managed runtime or event-loop.
20
+ *
21
+ * Some pseudo-code typical lifecycle of a connection might look something like
22
+ * this:
23
+ *
24
+ * trilogy_conn_t conn;
25
+ * trilogy_init(&conn);
26
+ *
27
+ * trilogy_connect_send(&conn, addrinfo);
28
+ *
29
+ * trilogy_handshake_t handshake;
30
+ * trilogy_connect_recv(&conn, &handshake);
31
+ *
32
+ * trilogy_auth_send(&conn, &handshake, "root", NULL, 0, 0);
33
+ * int rc = trilogy_auth_recv(&conn, &handshake);
34
+ * if (rc == TRILOGY_AUTH_SWITCH) {
35
+ * trilogy_auth_switch_send(&conn, &handshake);
36
+ * trilogy_auth_recv(&conn, &handshake);
37
+ * }
38
+ *
39
+ * At this point the connection is open, authenticated, and ready for commands.
40
+ * From here a caller can start issuing commands:
41
+ *
42
+ * char* db_name = "test";
43
+ * trilogy_change_db_send(&conn, db_name, strlen(db_name));
44
+ * trilogy_change_db_recv(&conn);
45
+ *
46
+ * Assuming the connection isn't in an error state, and all responses have been
47
+ * read off the network - it's ready for another command.
48
+ *
49
+ * Specific to the trilogy_query_send/trilogy_query_recv lifecycle - if
50
+ * TRILOGY_HAVE_RESULTS is returned from trilogy_query_recv, the caller *must* read
51
+ * all columns and rows from the server before the connection will be command-
52
+ * ready again. This is a requirement of a MySQL-compatible protocol.
53
+ *
54
+ * trilogy_close_send/trilogy_close_recv may be used to sent a quit command to the
55
+ * server. While this is considered best practice, simply calling trilogy_free
56
+ * to close the socket and free any internal buffers is enough to clean things
57
+ * up.
58
+ */
59
+
60
+ #define TRILOGY_DEFAULT_BUF_SIZE 32768
61
+
62
+ /* trilogy_column_t - The Trilogy client's column type.
63
+ */
64
+ typedef trilogy_column_packet_t trilogy_column_t;
65
+
66
+ /* trilogy_conn_t - The Trilogy client's instance type.
67
+ *
68
+ * This type is shared for the non-blocking and blocking versions of the API.
69
+ */
70
+ typedef struct {
71
+ uint64_t affected_rows;
72
+ uint64_t last_insert_id;
73
+ uint16_t warning_count;
74
+ char last_gtid[TRILOGY_MAX_LAST_GTID_LEN];
75
+ size_t last_gtid_len;
76
+
77
+ uint16_t error_code;
78
+ const char *error_message;
79
+ size_t error_message_len;
80
+
81
+ uint32_t capabilities;
82
+ uint16_t server_status;
83
+
84
+ trilogy_sock_t *socket;
85
+
86
+ // private:
87
+ uint8_t recv_buff[TRILOGY_DEFAULT_BUF_SIZE];
88
+ size_t recv_buff_pos;
89
+ size_t recv_buff_len;
90
+
91
+ trilogy_packet_parser_t packet_parser;
92
+ trilogy_buffer_t packet_buffer;
93
+ size_t packet_buffer_written;
94
+
95
+ uint64_t column_count;
96
+ bool started_reading_rows;
97
+ } trilogy_conn_t;
98
+
99
+ /* trilogy_init - Initialize a pre-allocated trilogy_conn_t pointer.
100
+ *
101
+ * conn - A pre-allocated trilogy_conn_t pointer.
102
+ *
103
+ * Return values:
104
+ * TRILOGY_OK - The trilogy_conn_t pointer was properly initialized
105
+ * TRILOGY_SYSERR - A system error occurred, check errno.
106
+ */
107
+ int trilogy_init(trilogy_conn_t *conn);
108
+
109
+ /* trilogy_flush_writes - Attempt to flush the internal packet buffer to the
110
+ * network. This must be used if a `_send` function returns TRILOGY_AGAIN, and
111
+ * should continue to be called until it returns a value other than
112
+ * TRILOGY_AGAIN.
113
+ *
114
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected trilogy_conn_t is
115
+ * undefined.
116
+ *
117
+ * Return values:
118
+ * TRILOGY_OK - The entire packet buffer has been written to the network.
119
+ * TRILOGY_AGAIN - Only part of the packet buffer was written to the network or
120
+ * the socket wasn't ready for writing. The caller should wait
121
+ * for writabilty using `conn->sock`. Then call this function
122
+ * until it returns a different value.
123
+ * TRILOGY_SYSERR - A system error occurred, check errno.
124
+ */
125
+ int trilogy_flush_writes(trilogy_conn_t *conn);
126
+
127
+ /* trilogy_connect_send - Create a socket and attempt initial connection to the
128
+ * server.
129
+ *
130
+ * conn - A pre-initialized trilogy_conn_t pointer.
131
+ * addr - A pre-initialized trilogy_sockopt_t pointer with the connection
132
+ * parameters.
133
+ *
134
+ * Return values:
135
+ * TRILOGY_OK - The socket was created and the initial connection has been
136
+ * established.
137
+ * TRILOGY_SYSERR - A system error occurred, check errno.
138
+ */
139
+ int trilogy_connect_send(trilogy_conn_t *conn, const trilogy_sockopt_t *opts);
140
+
141
+ /* trilogy_connect_send_socket - Attempt initial connection to the server using an
142
+ * existing trilogy_sock_t. The socket must _not_ have been connected yet.
143
+ *
144
+ * sock - An instance of trilogy_sock_t
145
+ *
146
+ * Return values:
147
+ * TRILOGY_OK - The socket was created and the initial connection has been
148
+ * established.
149
+ * TRILOGY_SYSERR - A system error occurred, check errno.
150
+ */
151
+ int trilogy_connect_send_socket(trilogy_conn_t *conn, trilogy_sock_t *sock);
152
+
153
+ /* trilogy_connect_recv - Read the initial handshake from the server.
154
+ *
155
+ * This should be called after trilogy_connect_send returns TRILOGY_OK. Calling
156
+ * this at any other time during the connection lifecycle is undefined.
157
+ *
158
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected
159
+ * trilogy_conn_t is undefined.
160
+ * handshake_out - A pre-allocated trilogy_handshake_t pointer. If TRILOGY_OK is
161
+ * returned, this struct will be filled out and ready to use.
162
+ *
163
+ * Return values:
164
+ * TRILOGY_OK - The initial handshake packet was read off the
165
+ * network.
166
+ * TRILOGY_AGAIN - The socket wasn't ready for reading. The caller
167
+ * should wait for readability using `conn->sock`.
168
+ * Then call this function again.
169
+ * TRILOGY_PROTOCOL_VIOLATION - An error occurred while processing a network
170
+ * packet.
171
+ * TRILOGY_CLOSED_CONNECTION - The connection is closed.
172
+ * TRILOGY_SYSERR - A system error occurred, check errno.
173
+ */
174
+ int trilogy_connect_recv(trilogy_conn_t *conn, trilogy_handshake_t *handshake_out);
175
+
176
+ /* trilogy_ssl_request_send - Send an SSL handshake request to the server.
177
+ *
178
+ * This should be called after a successful connection to the server. Calling
179
+ * this at any other time during the connection lifecycle is undefined. It is an
180
+ * error to call this function if TRILOGY_CAPABILITIES_SSL was not set by the
181
+ * server.
182
+ *
183
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected
184
+ * trilogy_conn_t is undefined.
185
+ *
186
+ * Return values:
187
+ * TRILOGY_OK - Authorization info was successfully sent to the server.
188
+ * TRILOGY_AGAIN - The socket wasn't ready for writing. The caller should wait
189
+ * for writeability using `conn->sock`. Then call
190
+ * trilogy_flush_writes.
191
+ * TRILOGY_SYSERR - A system error occurred, check errno.
192
+ */
193
+ int trilogy_ssl_request_send(trilogy_conn_t *conn);
194
+
195
+ /* trilogy_auth_send - Send a authorization info to the server.
196
+ *
197
+ * This should be called after a successful connection to the server. Calling
198
+ * this at any other time during the connection lifecycle is undefined.
199
+ *
200
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected
201
+ * trilogy_conn_t is undefined.
202
+ * handshake - A pre-initialized trilogy_handshake_t pointer.
203
+ *
204
+ * Return values:
205
+ * TRILOGY_OK - Authorization info was successfully sent to the server.
206
+ * TRILOGY_AGAIN - The socket wasn't ready for writing. The caller should wait
207
+ * for writeability using `conn->sock`. Then call
208
+ * trilogy_flush_writes.
209
+ * TRILOGY_SYSERR - A system error occurred, check errno.
210
+ */
211
+ int trilogy_auth_send(trilogy_conn_t *conn, const trilogy_handshake_t *handshake);
212
+
213
+ /* trilogy_auth_recv - Read the authorization response from the server.
214
+ *
215
+ * This should be called after all data written by trilogy_auth_send is flushed to
216
+ * the network. Calling this at any other time during the connection lifecycle
217
+ * is undefined.
218
+ *
219
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected trilogy_conn_t is
220
+ * undefined.
221
+ *
222
+ * Return values:
223
+ * TRILOGY_OK - Authorization completed successfully. The
224
+ * connection is ready for commands.
225
+ * TRILOGY_AUTH_SWITCH - The server requested an auth switch. Use
226
+ * `trilogy_auth_switch_send` to reply with the
227
+ * confirmation of the switch.
228
+ * TRILOGY_AGAIN - The socket wasn't ready for reading. The caller
229
+ * should wait for readability using `conn->sock`.
230
+ * Then call this function until it returns a
231
+ * different value.
232
+ * TRILOGY_UNEXPECTED_PACKET - The response packet wasn't what was expected.
233
+ * TRILOGY_PROTOCOL_VIOLATION - An error occurred while processing a network
234
+ * packet.
235
+ * TRILOGY_CLOSED_CONNECTION - The connection is closed.
236
+ * TRILOGY_SYSERR - A system error occurred, check errno.
237
+ */
238
+ int trilogy_auth_recv(trilogy_conn_t *conn, trilogy_handshake_t *handshake);
239
+
240
+ /* trilogy_auth_switch_send - Send a reply after an authentication switch request.
241
+ *
242
+ * This should be called after the server requests and auth switch. Calling
243
+ * this at any other time during the connection lifecycle is undefined.
244
+ *
245
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected trilogy_conn_t is undefined.
246
+ * handshake - A pre-initialized trilogy_handshake_t pointer.
247
+ *
248
+ * Return values:
249
+ * TRILOGY_OK - Authorization info was successfully sent to the server.
250
+ * TRILOGY_AGAIN - The socket wasn't ready for writing. The caller should wait
251
+ * for writeability using `conn->sock`. Then call
252
+ * trilogy_flush_writes.
253
+ * TRILOGY_SYSERR - A system error occurred, check errno.
254
+ */
255
+ int trilogy_auth_switch_send(trilogy_conn_t *conn, const trilogy_handshake_t *handshake);
256
+
257
+ /* trilogy_change_db_send - Send a change database command to the server. This
258
+ * will change the default database for this connection.
259
+ *
260
+ * This should only be called while the connection is ready for commands.
261
+ *
262
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected
263
+ * trilogy_conn_t is undefined.
264
+ * name - The name of the database.
265
+ * name_len - The length of the database name in bytes.
266
+ *
267
+ * Return values:
268
+ * TRILOGY_OK - The change database command was successfully sent to the
269
+ * server.
270
+ * TRILOGY_AGAIN - The socket wasn't ready for writing. The caller should wait
271
+ * for writeability using `conn->sock`. Then call
272
+ * trilogy_flush_writes.
273
+ * TRILOGY_SYSERR - A system error occurred, check errno.
274
+ */
275
+ int trilogy_change_db_send(trilogy_conn_t *conn, const char *name, size_t name_len);
276
+
277
+ /* trilogy_change_db_recv - Read the change database command response from the
278
+ * server.
279
+ *
280
+ * This should be called after all data written by trilogy_change_db_send is
281
+ * flushed to the network. Calling this at any other time during the connection
282
+ * lifecycle is undefined.
283
+ *
284
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected trilogy_conn_t is
285
+ * undefined.
286
+ *
287
+ * Return values:
288
+ * TRILOGY_OK - The change database command was successfully
289
+ * sent to the server.
290
+ * TRILOGY_AGAIN - The socket wasn't ready for reading. The
291
+ * caller should wait for readability using
292
+ * `conn->sock`. Then call this function until
293
+ * it returns a different value.
294
+ * TRILOGY_UNEXPECTED_PACKET - The response packet wasn't what was expected.
295
+ * TRILOGY_PROTOCOL_VIOLATION - An error occurred while processing a network
296
+ * packet.
297
+ * TRILOGY_CLOSED_CONNECTION - The connection is closed.
298
+ * TRILOGY_SYSERR - A system error occurred, check errno.
299
+ */
300
+ int trilogy_change_db_recv(trilogy_conn_t *conn);
301
+
302
+ /* trilogy_query_send - Send a query command to the server.
303
+ *
304
+ * This should only be called while the connection is ready for commands.
305
+ *
306
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected
307
+ * trilogy_conn_t is undefined.
308
+ * query - The query string.
309
+ * query_len - The length of query string in bytes.
310
+ *
311
+ * Return values:
312
+ * TRILOGY_OK - The query command was successfully sent to the server.
313
+ * TRILOGY_AGAIN - The socket wasn't ready for writing. The caller should
314
+ * wait for writeability using `conn->sock`. Then call
315
+ * trilogy_flush_writes.
316
+ * TRILOGY_SYSERR - A system error occurred, check errno.
317
+ */
318
+ int trilogy_query_send(trilogy_conn_t *conn, const char *query, size_t query_len);
319
+
320
+ /* trilogy_query_recv - Read the query command response from the server.
321
+ *
322
+ * This should be called after all data written by trilogy_query_send is flushed
323
+ * to the network. Calling this at any other time during the connection
324
+ * lifecycle is undefined.
325
+ *
326
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected
327
+ * trilogy_conn_t is undefined.
328
+ * column_count_out - Out parameter; If TRILOGY_HAVE_RESULTS is returned, this
329
+ * will be set to the number of columns in the result set.
330
+ *
331
+ * Return values:
332
+ * TRILOGY_OK - The query response was received and fully read.
333
+ * TRILOGY_HAVE_RESULTS - The query response was received and there are
334
+ * results to be read.
335
+ * TRILOGY_AGAIN - The socket wasn't ready for reading. The caller
336
+ * should wait for readability using `conn->sock`.
337
+ * Then call this function until it returns a
338
+ * different value.
339
+ * TRILOGY_UNEXPECTED_PACKET - The response packet wasn't what was expected.
340
+ * TRILOGY_PROTOCOL_VIOLATION - An error occurred while processing a network
341
+ * packet.
342
+ * TRILOGY_CLOSED_CONNECTION - The connection is closed.
343
+ * TRILOGY_SYSERR - A system error occurred, check errno.
344
+ */
345
+ int trilogy_query_recv(trilogy_conn_t *conn, uint64_t *column_count_out);
346
+
347
+ /* trilogy_read_column - Read a column from the result set.
348
+ *
349
+ * This should be called as many times as there are columns in the result set.
350
+ * Calling this more times than that is undefined. This should also only be
351
+ * called after a query command has completed and returned TRILOGY_HAVE_RESULTS.
352
+ * Calling this at any other time during the connection lifecycle is undefined.
353
+ *
354
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected
355
+ * trilogy_conn_t is undefined.
356
+ * column_out - Out parameter; A pointer to a pre-allocated trilogy_column_t. If
357
+ * TRILOGY_OK is returned this will be filled out. This value will be
358
+ * invalid after any other call to this API. The caller should make
359
+ * a copy if they want to keep the value around.
360
+ *
361
+ * Return values:
362
+ * TRILOGY_OK - The column was successfully read.
363
+ * TRILOGY_AGAIN - The socket wasn't ready for reading. The caller
364
+ * should wait for readability using `conn->sock`.
365
+ * Then call this function until it returns a
366
+ * different value.
367
+ * TRILOGY_UNEXPECTED_PACKET - The response packet wasn't what was expected.
368
+ * TRILOGY_PROTOCOL_VIOLATION - An error occurred while processing a network
369
+ * packet.
370
+ * TRILOGY_CLOSED_CONNECTION - The connection is closed.
371
+ * TRILOGY_SYSERR - A system error occurred, check errno.
372
+ */
373
+ int trilogy_read_column(trilogy_conn_t *conn, trilogy_column_t *column_out);
374
+
375
+ /* trilogy_read_row - Read a column from the result set.
376
+ *
377
+ * This should be called after reading all columns from the network. Calling
378
+ * this at any other time during the connection lifecycle is undefined.
379
+ *
380
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected
381
+ * trilogy_conn_t is undefined.
382
+ * values_out - Out parameter; A pre-allocated trilogy_value_t pointer, which will
383
+ * be filled out by this function. It should be allocated with
384
+ * enough space to hold a trilogy_value_t pointer for each column.
385
+ * Something like: `(sizeof(trilogy_value_t) * column_count)`. This
386
+ * pointer is invalid after any other call to this API. The caller
387
+ * should make a copy of the values inside if they want to keep
388
+ * them around.
389
+ *
390
+ * Return values:
391
+ * TRILOGY_OK - The query response was received and fully read.
392
+ * TRILOGY_EOF - There are no more rows to be read.
393
+ * TRILOGY_AGAIN - The socket wasn't ready for reading. The caller
394
+ * should wait for readability using `conn->sock`.
395
+ * Then call this function until it returns a
396
+ * different value.
397
+ * TRILOGY_UNEXPECTED_PACKET - The response packet wasn't what was expected.
398
+ * TRILOGY_PROTOCOL_VIOLATION - An error occurred while processing a network
399
+ * packet.
400
+ * TRILOGY_CLOSED_CONNECTION - The connection is closed.
401
+ * TRILOGY_SYSERR - A system error occurred, check errno.
402
+ */
403
+ int trilogy_read_row(trilogy_conn_t *conn, trilogy_value_t *values_out);
404
+
405
+ /* trilogy_drain_results - A convenience function to read and throw away the
406
+ * remaining rows from a result set. Any MySQL-compatible protocol requires that all
407
+ * responses from a command are read off the network before any other commands
408
+ * can be issued. A caller could otherwise do the same thing this function does
409
+ * by calling trilogy_read_row until it returns TRILOGY_EOF. But this call does that
410
+ * in a much more efficient manner by only reading packet frames then throwing
411
+ * them away, skipping the parsing of value information from inside each packet.
412
+ *
413
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected trilogy_conn_t is
414
+ * undefined.
415
+ *
416
+ * Return values:
417
+ * TRILOGY_OK - The rest of the result was drained and the
418
+ * connection is ready for another command.
419
+ * TRILOGY_AGAIN - The socket wasn't ready for reading. The caller
420
+ * should wait for readability using `conn->sock`.
421
+ * Then call this function until it returns a
422
+ * different value.
423
+ * TRILOGY_UNEXPECTED_PACKET - The response packet wasn't what was expected.
424
+ * TRILOGY_PROTOCOL_VIOLATION - An error occurred while processing a network
425
+ * packet.
426
+ * TRILOGY_CLOSED_CONNECTION - The connection is closed.
427
+ * TRILOGY_SYSERR - A system error occurred, check errno.
428
+ */
429
+ int trilogy_drain_results(trilogy_conn_t *conn);
430
+
431
+ /* trilogy_ping_send - Send a ping command to the server.
432
+ *
433
+ * This should only be called while the connection is ready for commands.
434
+ *
435
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected trilogy_conn_t
436
+ * is undefined.
437
+ *
438
+ * Return values:
439
+ * TRILOGY_OK - The ping command was successfully sent to the server.
440
+ * TRILOGY_AGAIN - The socket wasn't ready for writing. The caller should wait
441
+ * for writeability using `conn->sock`. Then call
442
+ * trilogy_flush_writes.
443
+ * TRILOGY_SYSERR - A system error occurred, check errno.
444
+ */
445
+ int trilogy_ping_send(trilogy_conn_t *conn);
446
+
447
+ /* trilogy_ping_recv - Read the ping command response from the server.
448
+ *
449
+ * This should be called after all data written by trilogy_ping_send is flushed to
450
+ * the network. Calling this at any other time during the connection lifecycle
451
+ * is undefined.
452
+ *
453
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected trilogy_conn_t is
454
+ * undefined.
455
+ *
456
+ * Return values:
457
+ * TRILOGY_OK - The ping command was successfully sent to the
458
+ * server.
459
+ * TRILOGY_AGAIN - The socket wasn't ready for reading. The caller
460
+ * should wait for readability using `conn->sock`.
461
+ * Then call this function until it returns a
462
+ * different value.
463
+ * TRILOGY_UNEXPECTED_PACKET - The response packet wasn't what was expected.
464
+ * TRILOGY_PROTOCOL_VIOLATION - An error occurred while processing a network
465
+ * packet.
466
+ * TRILOGY_CLOSED_CONNECTION - The connection is closed.
467
+ * TRILOGY_SYSERR - A system error occurred, check errno.
468
+ */
469
+ int trilogy_ping_recv(trilogy_conn_t *conn);
470
+
471
+ /* trilogy_escape - Escape a string, making it safe to use in a query.
472
+ *
473
+ * This function assumes the input is in an ASCII-compatible encoding. Passing
474
+ * in a string in any other encoding is undefined and will likely corrupt the
475
+ * input. Potentially leaving the caller open to SQL-injection style attacks.
476
+ *
477
+ * If the TRILOGY_SERVER_STATUS_NO_BACKSLASH_ESCAPES flag is set, it will disable
478
+ * the use of the backslash character ("\") as an escape character. Making
479
+ * backslash an ordinary character like any other.
480
+ *
481
+ * That mode can be enabled at runtime by issuing setting the
482
+ * NO_BACKSLASH_ESCAPES sql mode. This can be done with a query like:
483
+ * "SET SQL_MODE=NO_BACKSLASH_ESCAPES"
484
+ *
485
+ * conn - A pre-initialized trilogy_conn_t pointer.
486
+ * str - The string to be escaped.
487
+ * len - The length of `str` in bytes.
488
+ * escaped_str_out - Out parameter; The dereferenced value of this pointer will
489
+ * point to the escaped version of `str` if TRILOGY_OK was
490
+ * returned.
491
+ * escaped_len_out - Out parameter; The length of the buffer `escaped_str_out`
492
+ * points to if TRILOGY_OK was returned.
493
+ *
494
+ * Return values:
495
+ * TRILOGY_OK - The input string has been processed.
496
+ * TRILOGY_SYSERR - A system error occurred, check errno.
497
+ */
498
+ int trilogy_escape(trilogy_conn_t *conn, const char *str, size_t len, const char **escaped_str_out,
499
+ size_t *escaped_len_out);
500
+
501
+ /* trilogy_close_send - Send a quit command to the server.
502
+ *
503
+ * conn - A connected trilogy_conn_t pointer. Using a disconnected trilogy_conn_t is
504
+ * undefined.
505
+ *
506
+ * Return values:
507
+ * TRILOGY_OK - The quit command was successfully sent to the server.
508
+ * TRILOGY_AGAIN - The socket wasn't ready for writing. The caller should wait
509
+ * for writeability using `conn->sock`. Then call
510
+ * trilogy_flush_writes.
511
+ * TRILOGY_SYSERR - A system error occurred, check errno.
512
+ */
513
+ int trilogy_close_send(trilogy_conn_t *conn);
514
+
515
+ /* trilogy_close_recv - Read the quit command response from the MySQL-compatible server.
516
+ *
517
+ * This should be called after all data written by trilogy_close_send is flushed
518
+ * to the network. Calling this at any other time during the connection
519
+ * lifecycle is undefined.
520
+ *
521
+ * conn - A pre-initialized trilogy_conn_t pointer. It can also be connected but
522
+ * a disconnected trilogy_conn_t will also return TRILOGY_OK.
523
+ *
524
+ * Return values:
525
+ * TRILOGY_OK - The quit command response successfully read from
526
+ * the server.
527
+ * TRILOGY_AGAIN - The socket wasn't ready for reading. The caller
528
+ * should wait for readability using `conn->sock`.
529
+ * Then call this function until it returns a
530
+ * different value.
531
+ * TRILOGY_UNEXPECTED_PACKET - The response packet wasn't what was expected.
532
+ * TRILOGY_PROTOCOL_VIOLATION - An error occurred while processing a network
533
+ * packet.
534
+ * TRILOGY_SYSERR - A system error occurred, check errno.
535
+ */
536
+ int trilogy_close_recv(trilogy_conn_t *conn);
537
+
538
+ /* trilogy_free - Close the connection and free any internal buffers.
539
+ *
540
+ * conn - A pre-initialized trilogy_conn_t pointer.
541
+ *
542
+ * Returns nothing.
543
+ */
544
+ void trilogy_free(trilogy_conn_t *conn);
545
+
546
+ #endif
@@ -0,0 +1,43 @@
1
+ #ifndef TRILOGY_ERROR_H
2
+ #define TRILOGY_ERROR_H
3
+
4
+ #define TRILOGY_ERROR_CODES(XX) \
5
+ XX(TRILOGY_OK, 0) \
6
+ XX(TRILOGY_ERR, -1) \
7
+ XX(TRILOGY_EOF, -2) \
8
+ XX(TRILOGY_SYSERR, -3) /* check errno */ \
9
+ XX(TRILOGY_UNEXPECTED_PACKET, -4) \
10
+ XX(TRILOGY_TRUNCATED_PACKET, -5) \
11
+ XX(TRILOGY_PROTOCOL_VIOLATION, -6) \
12
+ XX(TRILOGY_AUTH_PLUGIN_TOO_LONG, -7) \
13
+ XX(TRILOGY_EXTRA_DATA_IN_PACKET, -8) \
14
+ XX(TRILOGY_INVALID_CHARSET, -9) \
15
+ XX(TRILOGY_AGAIN, -10) \
16
+ XX(TRILOGY_CLOSED_CONNECTION, -11) \
17
+ XX(TRILOGY_HAVE_RESULTS, -12) \
18
+ XX(TRILOGY_NULL_VALUE, -13) \
19
+ XX(TRILOGY_INVALID_SEQUENCE_ID, -14) \
20
+ XX(TRILOGY_TYPE_OVERFLOW, -15) \
21
+ XX(TRILOGY_OPENSSL_ERR, -16) /* check ERR_get_error() */ \
22
+ XX(TRILOGY_UNSUPPORTED, -17) \
23
+ XX(TRILOGY_DNS_ERR, -18) \
24
+ XX(TRILOGY_AUTH_SWITCH, -19)
25
+
26
+ enum {
27
+ #define XX(name, code) name = code,
28
+ TRILOGY_ERROR_CODES(XX)
29
+ #undef XX
30
+ };
31
+
32
+ /* trilogy_error - Get the string version of an Trilogy error code.
33
+ *
34
+ * This can be useful for logging or debugging as printing the error value
35
+ * integer itself doesn't provide much context.
36
+ *
37
+ * error - An Trilogy error code integer.
38
+ *
39
+ * Returns an error name constant from TRILOGY_ERROR_CODES as a C-string.
40
+ */
41
+ const char *trilogy_error(int error);
42
+
43
+ #endif
@@ -0,0 +1,34 @@
1
+ #ifndef TRILOGY_PACKET_PARSER_H
2
+ #define TRILOGY_PACKET_PARSER_H
3
+
4
+ #include <stddef.h>
5
+ #include <stdint.h>
6
+
7
+ // Data between client and server is exchanged in packets of max 16MByte size.
8
+ #define TRILOGY_MAX_PACKET_LEN 0xffffff
9
+
10
+ typedef struct {
11
+ int (*on_packet_begin)(void *);
12
+ int (*on_packet_data)(void *, const uint8_t *, size_t);
13
+ int (*on_packet_end)(void *);
14
+ } trilogy_packet_parser_callbacks_t;
15
+
16
+ typedef struct {
17
+ void *user_data;
18
+ const trilogy_packet_parser_callbacks_t *callbacks;
19
+
20
+ uint8_t sequence_number;
21
+
22
+ // private:
23
+ unsigned bytes_remaining : 24;
24
+
25
+ unsigned state : 3;
26
+ unsigned fragment : 1;
27
+ unsigned deferred_end_callback : 1;
28
+ } trilogy_packet_parser_t;
29
+
30
+ void trilogy_packet_parser_init(trilogy_packet_parser_t *parser, const trilogy_packet_parser_callbacks_t *callbacks);
31
+
32
+ size_t trilogy_packet_parser_execute(trilogy_packet_parser_t *parser, const uint8_t *buf, size_t len, int *error);
33
+
34
+ #endif