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,212 @@
1
+ #ifndef TRILOGY_READER_H
2
+ #define TRILOGY_READER_H
3
+
4
+ #include <stdbool.h>
5
+ #include <stddef.h>
6
+ #include <stdint.h>
7
+
8
+ /* Trilogy Packet Reader API
9
+ *
10
+ * The packet reader API is used to parse MySQL-compatible protocol packets.
11
+ */
12
+
13
+ /* trilogy_reader_t - The reader API's instance type.
14
+ */
15
+ typedef struct {
16
+ const uint8_t *buff;
17
+ size_t len;
18
+ size_t pos;
19
+ } trilogy_reader_t;
20
+
21
+ /* trilogy_reader_init - Initialize a pre-allocated trilogy_reader_t.
22
+ *
23
+ * reader - A pointer to a pre-allocated trilogy_reader_t.
24
+ * buff - A pointer to a buffer containing MySQL-compatible protocol packet data.
25
+ * len - The length of `buff` in bytes.
26
+ *
27
+ * Returns nothing.
28
+ */
29
+ void trilogy_reader_init(trilogy_reader_t *reader, const uint8_t *buff, size_t len);
30
+
31
+ #define TRILOGY_READER(buffer, length) ((trilogy_reader_t){.buff = (buffer), .len = (length), .pos = 0});
32
+
33
+ /* trilogy_reader_get_uint8 - Parse an unsigned 8-bit integer.
34
+ *
35
+ * reader - A pointer to a pre-initialized trilogy_reader_t.
36
+ * out - Out parameter; A pointer to a uint8_t which will be set to the
37
+ * value read from the buffer.
38
+ *
39
+ * Return values:
40
+ * TRILOGY_OK - The value was parsed.
41
+ * TRILOGY_TRUNCATED_PACKET - There isn't enough data left in the buffer.
42
+ */
43
+ int trilogy_reader_get_uint8(trilogy_reader_t *reader, uint8_t *out);
44
+
45
+ /* trilogy_reader_get_uint16 - Parse an unsigned 16-bit integer.
46
+ *
47
+ * reader - A pointer to a pre-initialized trilogy_reader_t.
48
+ * out - Out parameter; A pointer to a uint16_t which will be set to the
49
+ * value read from the buffer.
50
+ *
51
+ * Return values:
52
+ * TRILOGY_OK - The value was parsed.
53
+ * TRILOGY_TRUNCATED_PACKET - There isn't enough data left in the buffer.
54
+ */
55
+ int trilogy_reader_get_uint16(trilogy_reader_t *reader, uint16_t *out);
56
+
57
+ /* trilogy_reader_get_uint24 - Parse an unsigned 24-bit integer.
58
+ *
59
+ * reader - A pointer to a pre-initialized trilogy_reader_t.
60
+ * out - Out parameter; A pointer to a uint32_t which will be set to the
61
+ * value read from the buffer.
62
+ *
63
+ * Return values:
64
+ * TRILOGY_OK - The value was parsed.
65
+ * TRILOGY_TRUNCATED_PACKET - There isn't enough data left in the buffer.
66
+ */
67
+ int trilogy_reader_get_uint24(trilogy_reader_t *reader, uint32_t *out);
68
+
69
+ /* trilogy_reader_get_uint32 - Parse an unsigned 32-bit integer.
70
+ *
71
+ * reader - A pointer to a pre-initialized trilogy_reader_t.
72
+ * out - Out parameter; A pointer to a uint32_t which will be set to the
73
+ * value read from the buffer.
74
+ *
75
+ * Return values:
76
+ * TRILOGY_OK - The value was parsed.
77
+ * TRILOGY_TRUNCATED_PACKET - There isn't enough data left in the buffer.
78
+ */
79
+ int trilogy_reader_get_uint32(trilogy_reader_t *reader, uint32_t *out);
80
+
81
+ /* trilogy_reader_get_uint64 - Parse an unsigned 64-bit integer.
82
+ *
83
+ * reader - A pointer to a pre-initialized trilogy_reader_t.
84
+ * out - Out parameter; A pointer to a uint64_t which will be set to the
85
+ * value read from the buffer.
86
+ *
87
+ * Return values:
88
+ * TRILOGY_OK - The value was parsed.
89
+ * TRILOGY_TRUNCATED_PACKET - There isn't enough data left in the buffer.
90
+ */
91
+ int trilogy_reader_get_uint64(trilogy_reader_t *reader, uint64_t *out);
92
+
93
+ /* trilogy_reader_get_lenenc - Parse an unsigned, length-encoded integer.
94
+ *
95
+ * reader - A pointer to a pre-initialized trilogy_reader_t.
96
+ * out - Out parameter; A pointer to a uint64_t which will be set to the
97
+ * value read from the buffer.
98
+ *
99
+ * Return values:
100
+ * TRILOGY_OK - The value was parsed.
101
+ * TRILOGY_TRUNCATED_PACKET - There isn't enough data left in the buffer.
102
+ */
103
+ int trilogy_reader_get_lenenc(trilogy_reader_t *reader, uint64_t *out);
104
+
105
+ /* trilogy_reader_get_buffer - Parse an opaque set of bytes from the packet,
106
+ * pointing the dereferenced value of `out` to the beginning of the set.
107
+ *
108
+ * reader - A pointer to a pre-initialized trilogy_reader_t.
109
+ * len - The number of bytes to attempt to read from the buffer.
110
+ * out - Out parameter; A pointer to a void* which will be set to the
111
+ * beginning of the opaque buffer. This will be a pointer into the
112
+ * buffer that was originally passed to trilogy_reader_init. No copies
113
+ * are made internally.
114
+ *
115
+ * Return values:
116
+ * TRILOGY_OK - The value was parsed and the dereferenced value of
117
+ * `out` now points to it.
118
+ * TRILOGY_TRUNCATED_PACKET - There isn't enough data left in the buffer.
119
+ */
120
+ int trilogy_reader_get_buffer(trilogy_reader_t *reader, size_t len, const void **out);
121
+
122
+ /* trilogy_reader_copy_buffer - Parse an opaque set of bytes from the packet and
123
+ * copy them into `out`. `out` must be allocated with at least `len` bytes.
124
+ *
125
+ * reader - A pointer to a pre-initialized trilogy_reader_t.
126
+ * len - The number of bytes to attempt to read from the buffer.
127
+ * out - A pointer to the address to copy `len` bytes from the packet buffer
128
+ * to.
129
+ *
130
+ * Return values:
131
+ * TRILOGY_OK - The value was parsed and copied into the location
132
+ * `out` points to.
133
+ * TRILOGY_TRUNCATED_PACKET - There isn't enough data left in the buffer.
134
+ */
135
+ int trilogy_reader_copy_buffer(trilogy_reader_t *reader, size_t len, void *out);
136
+
137
+ /* trilogy_reader_get_lenenc_buffer - Parse an opaque set of bytes from the
138
+ * packet, pointing the dereferenced value of `out` to the beginning of the set.
139
+ * The length of the buffer is defined by a preceding length-encoded integer,
140
+ * who's value will be copied in to `out_len`.
141
+ *
142
+ * reader - A pointer to a pre-initialized trilogy_reader_t.
143
+ * out_len - Out parameter; The length of the read buffer in bytes.
144
+ * out - Out parameter; A pointer to a void* which will be set to the
145
+ * beginning of the opaque buffer.
146
+ *
147
+ * Return values:
148
+ * TRILOGY_OK - The value was parsed and the dereferenced value of
149
+ * `out` now points to it.
150
+ * TRILOGY_TRUNCATED_PACKET - There isn't enough data left in the buffer.
151
+ */
152
+ int trilogy_reader_get_lenenc_buffer(trilogy_reader_t *reader, size_t *out_len, const void **out);
153
+
154
+ /* trilogy_reader_get_string - Parse a C-string from the packet, pointing the
155
+ * dereferenced value of `out` to the beginning of the set.
156
+ *
157
+ * reader - A pointer to a pre-initialized trilogy_reader_t.
158
+ * out_len - Out parameter; The length of the C-string read from the buffer in
159
+ * bytes.
160
+ * out - Out parameter; A pointer to a void* which will be set to the
161
+ * beginning of the C-string.
162
+ *
163
+ * Return values:
164
+ * TRILOGY_OK - The value was parsed and the dereferenced value of
165
+ * `out` now points to it.
166
+ * TRILOGY_TRUNCATED_PACKET - There isn't enough data left in the buffer.
167
+ */
168
+ int trilogy_reader_get_string(trilogy_reader_t *reader, const char **out, size_t *out_len);
169
+
170
+ /* trilogy_reader_get_eof_buffer - Parse an opaque set of bytes from the packet,
171
+ * pointing the dereferenced value of `out` to the beginning of the set. The
172
+ * buffer pointed to by `out` will contain the remaining un-parsed bytes from
173
+ * the packet buffer.
174
+ *
175
+ * This will just hand the caller back a pointer into the remainder of the
176
+ * buffer, even if there aren't any more bytes left to read. As a result, this
177
+ * function will only ever return TRILOGY_OK.
178
+ *
179
+ * reader - A pointer to a pre-initialized trilogy_reader_t.
180
+ * out_len - Out parameter; The length of the read buffer in bytes.
181
+ * out - Out parameter; A pointer to a void* which will be set to the
182
+ * beginning of the opaque buffer.
183
+ *
184
+ * Return values:
185
+ * TRILOGY_OK - The value was parsed and the dereferenced value of
186
+ * `out` now points to it.
187
+ */
188
+ int trilogy_reader_get_eof_buffer(trilogy_reader_t *reader, size_t *out_len, const void **out);
189
+
190
+ /* trilogy_reader_eof - Check if the reader is at the end of the buffer.
191
+ *
192
+ * reader - A pointer to a pre-initialized trilogy_reader_t.
193
+ *
194
+ * Returns true if the reader is at the end of the buffer it's reading from,
195
+ * or false if not
196
+ */
197
+ bool trilogy_reader_eof(trilogy_reader_t *reader);
198
+
199
+ /* trilogy_reader_finish - Finalize the reader. This will ensure the entire buffer
200
+ * was parsed, otherwise TRILOGY_EXTRA_DATA_IN_PACKET will be returned.
201
+ *
202
+ * This can be useful to ensure an entire packet is fully read.
203
+ *
204
+ * reader - A pointer to a pre-initialized trilogy_reader_t.
205
+ *
206
+ * Return values:
207
+ * TRILOGY_OK - The entire buffer was parsed.
208
+ * TRILOGY_EXTRA_DATA_IN_PACKET - There are unparsed bytes left in the buffer.
209
+ */
210
+ int trilogy_reader_finish(trilogy_reader_t *reader);
211
+
212
+ #endif
@@ -0,0 +1,111 @@
1
+ #ifndef TRILOGY_SOCKET_H
2
+ #define TRILOGY_SOCKET_H
3
+
4
+ #include "trilogy/error.h"
5
+ #include "trilogy/protocol.h"
6
+ #include <openssl/err.h>
7
+ #include <openssl/ssl.h>
8
+ #include <openssl/x509v3.h>
9
+ #include <stdbool.h>
10
+ #include <sys/time.h>
11
+
12
+ typedef enum {
13
+ TRILOGY_WAIT_READ = 0,
14
+ TRILOGY_WAIT_WRITE = 1,
15
+ TRILOGY_WAIT_HANDSHAKE = 2,
16
+ } trilogy_wait_t;
17
+
18
+ // We use the most strict mode as value 1 so if anyone ever
19
+ // treats this as a boolean, they get the most strict behavior
20
+ // by default.
21
+ typedef enum {
22
+ TRILOGY_SSL_DISABLED = 0,
23
+ TRILOGY_SSL_VERIFY_IDENTITY = 1,
24
+ TRILOGY_SSL_VERIFY_CA = 2,
25
+ TRILOGY_SSL_REQUIRED_NOVERIFY = 3,
26
+ TRILOGY_SSL_PREFERRED_NOVERIFY = 4,
27
+ } trilogy_ssl_mode_t;
28
+
29
+ typedef enum {
30
+ TRILOGY_TLS_VERSION_UNDEF = 0,
31
+ TRILOGY_TLS_VERSION_10 = 1,
32
+ TRILOGY_TLS_VERSION_11 = 2,
33
+ TRILOGY_TLS_VERSION_12 = 3,
34
+ TRILOGY_TLS_VERSION_13 = 4,
35
+ } trilogy_tls_version_t;
36
+
37
+ typedef struct {
38
+ char *hostname;
39
+ char *path;
40
+ char *database;
41
+ char *username;
42
+ char *password;
43
+ size_t password_len;
44
+
45
+ trilogy_ssl_mode_t ssl_mode;
46
+ trilogy_tls_version_t tls_min_version;
47
+ trilogy_tls_version_t tls_max_version;
48
+ uint16_t port;
49
+
50
+ char *ssl_ca;
51
+ char *ssl_capath;
52
+ char *ssl_cert;
53
+ char *ssl_cipher;
54
+ char *ssl_crl;
55
+ char *ssl_crlpath;
56
+ char *ssl_key;
57
+ char *tls_ciphersuites;
58
+
59
+ struct timeval connect_timeout;
60
+ struct timeval read_timeout;
61
+ struct timeval write_timeout;
62
+
63
+ bool keepalive_enabled;
64
+ uint16_t keepalive_idle;
65
+ uint16_t keepalive_count;
66
+ uint16_t keepalive_interval;
67
+
68
+ TRILOGY_CAPABILITIES_t flags;
69
+ } trilogy_sockopt_t;
70
+
71
+ typedef struct trilogy_sock_t {
72
+ int (*connect_cb)(struct trilogy_sock_t *self);
73
+ ssize_t (*read_cb)(struct trilogy_sock_t *self, void *buf, size_t nread);
74
+ ssize_t (*write_cb)(struct trilogy_sock_t *self, const void *buf, size_t nwrite);
75
+ int (*wait_cb)(struct trilogy_sock_t *self, trilogy_wait_t wait);
76
+ int (*shutdown_cb)(struct trilogy_sock_t *self);
77
+ int (*close_cb)(struct trilogy_sock_t *self);
78
+ int (*fd_cb)(struct trilogy_sock_t *self);
79
+
80
+ trilogy_sockopt_t opts;
81
+ } trilogy_sock_t;
82
+
83
+ static inline int trilogy_sock_connect(trilogy_sock_t *sock) { return sock->connect_cb(sock); }
84
+
85
+ static inline ssize_t trilogy_sock_read(trilogy_sock_t *sock, void *buf, size_t n)
86
+ {
87
+ return sock->read_cb(sock, buf, n);
88
+ }
89
+
90
+ static inline ssize_t trilogy_sock_write(trilogy_sock_t *sock, const void *buf, size_t n)
91
+ {
92
+ return sock->write_cb(sock, buf, n);
93
+ }
94
+
95
+ static inline int trilogy_sock_wait(trilogy_sock_t *sock, trilogy_wait_t wait) { return sock->wait_cb(sock, wait); }
96
+
97
+ static inline int trilogy_sock_wait_read(trilogy_sock_t *sock) { return sock->wait_cb(sock, TRILOGY_WAIT_READ); }
98
+
99
+ static inline int trilogy_sock_wait_write(trilogy_sock_t *sock) { return sock->wait_cb(sock, TRILOGY_WAIT_WRITE); }
100
+
101
+ static inline int trilogy_sock_shutdown(trilogy_sock_t *sock) { return sock->shutdown_cb(sock); }
102
+
103
+ static inline int trilogy_sock_close(trilogy_sock_t *sock) { return sock->close_cb(sock); }
104
+
105
+ static inline int trilogy_sock_fd(trilogy_sock_t *sock) { return sock->fd_cb(sock); }
106
+
107
+ trilogy_sock_t *trilogy_sock_new(const trilogy_sockopt_t *opts);
108
+ int trilogy_sock_resolve(trilogy_sock_t *raw);
109
+ int trilogy_sock_upgrade_ssl(trilogy_sock_t *raw);
110
+
111
+ #endif
@@ -0,0 +1,29 @@
1
+ #ifndef HEADER_CURL_HOSTCHECK_H
2
+ #define HEADER_CURL_HOSTCHECK_H
3
+ /***************************************************************************
4
+ * _ _ ____ _
5
+ * Project ___| | | | _ \| |
6
+ * / __| | | | |_) | |
7
+ * | (__| |_| | _ <| |___
8
+ * \___|\___/|_| \_\_____|
9
+ *
10
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
11
+ *
12
+ * This software is licensed as described in the file COPYING, which
13
+ * you should have received as part of this distribution. The terms
14
+ * are also available at http://curl.haxx.se/docs/copyright.html.
15
+ *
16
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
17
+ * copies of the Software, and permit persons to whom the Software is
18
+ * furnished to do so, under the terms of the COPYING file.
19
+ *
20
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21
+ * KIND, either express or implied.
22
+ *
23
+ ***************************************************************************/
24
+
25
+ #define CURL_HOST_NOMATCH 0
26
+ #define CURL_HOST_MATCH 1
27
+ int Curl_cert_hostcheck(const char *match_pattern, const char *hostname);
28
+
29
+ #endif /* HEADER_CURL_HOSTCHECK_H */
@@ -0,0 +1,51 @@
1
+ #ifndef HEADER_OPENSSL_HOSTNAME_VALIDATION_H
2
+ #define HEADER_OPENSSL_HOSTNAME_VALIDATION_H
3
+ /* Obtained from: https://github.com/iSECPartners/ssl-conservatory */
4
+
5
+ /*
6
+ Copyright (C) 2012, iSEC Partners.
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
8
+ this software and associated documentation files (the "Software"), to deal in
9
+ the Software without restriction, including without limitation the rights to
10
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11
+ of the Software, and to permit persons to whom the Software is furnished to do
12
+ so, subject to the following conditions:
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+ */
23
+
24
+ /*
25
+ * Helper functions to perform basic hostname validation using OpenSSL.
26
+ *
27
+ * Please read "everything-you-wanted-to-know-about-openssl.pdf" before
28
+ * attempting to use this code. This whitepaper describes how the code works,
29
+ * how it should be used, and what its limitations are.
30
+ *
31
+ * Author: Alban Diquet
32
+ * License: See LICENSE
33
+ *
34
+ */
35
+
36
+ typedef enum { MatchFound, MatchNotFound, NoSANPresent, MalformedCertificate, Error } HostnameValidationResult;
37
+
38
+ /**
39
+ * Validates the server's identity by looking for the expected hostname in the
40
+ * server's certificate. As described in RFC 6125, it first tries to find a
41
+ * match in the Subject Alternative Name extension. If the extension is not
42
+ * present in the certificate, it checks the Common Name instead.
43
+ *
44
+ * Returns MatchFound if a match was found.
45
+ * Returns MatchNotFound if no matches were found.
46
+ * Returns MalformedCertificate if any of the hostnames had a NUL character
47
+ * embedded in it. Returns Error if there was an error.
48
+ */
49
+ HostnameValidationResult validate_hostname(const char *hostname, const X509 *server_cert);
50
+
51
+ #endif /* HEADER_OPENSSL_HOSTNAME_VALIDATION_H */
@@ -0,0 +1,8 @@
1
+ #ifndef TRILOGY_H
2
+ #define TRILOGY_H
3
+
4
+ #include "trilogy/blocking.h"
5
+ #include "trilogy/client.h"
6
+ #include "trilogy/error.h"
7
+
8
+ #endif
@@ -0,0 +1,241 @@
1
+ #include <errno.h>
2
+ #include <poll.h>
3
+
4
+ #include "trilogy/blocking.h"
5
+ #include "trilogy/client.h"
6
+ #include "trilogy/error.h"
7
+
8
+ #define CHECKED(expr) \
9
+ if ((rc = (expr)) < 0) { \
10
+ return rc; \
11
+ }
12
+
13
+ static int flush_full(trilogy_conn_t *conn)
14
+ {
15
+ int rc;
16
+
17
+ while (1) {
18
+ CHECKED(trilogy_sock_wait_write(conn->socket));
19
+
20
+ rc = trilogy_flush_writes(conn);
21
+
22
+ if (rc != TRILOGY_AGAIN) {
23
+ return rc;
24
+ }
25
+ }
26
+ }
27
+
28
+ static int trilogy_connect_auth_switch(trilogy_conn_t *conn, trilogy_handshake_t *handshake)
29
+ {
30
+ int rc = trilogy_auth_switch_send(conn, handshake);
31
+
32
+ if (rc == TRILOGY_AGAIN) {
33
+ rc = flush_full(conn);
34
+ }
35
+
36
+ if (rc < 0) {
37
+ return rc;
38
+ }
39
+
40
+ while (1) {
41
+ rc = trilogy_auth_recv(conn, handshake);
42
+
43
+ if (rc != TRILOGY_AGAIN) {
44
+ break;
45
+ }
46
+
47
+ CHECKED(trilogy_sock_wait_read(conn->socket));
48
+ }
49
+ return rc;
50
+ }
51
+
52
+ static int trilogy_connect_handshake(trilogy_conn_t *conn)
53
+ {
54
+ trilogy_handshake_t handshake;
55
+ int rc;
56
+
57
+ while (1) {
58
+ rc = trilogy_connect_recv(conn, &handshake);
59
+
60
+ if (rc == TRILOGY_OK) {
61
+ break;
62
+ }
63
+
64
+ if (rc != TRILOGY_AGAIN) {
65
+ return rc;
66
+ }
67
+
68
+ CHECKED(trilogy_sock_wait_read(conn->socket));
69
+ }
70
+
71
+ rc = trilogy_auth_send(conn, &handshake);
72
+
73
+ if (rc == TRILOGY_AGAIN) {
74
+ rc = flush_full(conn);
75
+ }
76
+
77
+ if (rc < 0) {
78
+ return rc;
79
+ }
80
+
81
+ while (1) {
82
+ rc = trilogy_auth_recv(conn, &handshake);
83
+
84
+ if (rc != TRILOGY_AGAIN) {
85
+ break;
86
+ }
87
+
88
+ CHECKED(trilogy_sock_wait_read(conn->socket));
89
+ }
90
+
91
+ if (rc == TRILOGY_AUTH_SWITCH) {
92
+ return trilogy_connect_auth_switch(conn, &handshake);
93
+ }
94
+ return rc;
95
+ }
96
+
97
+ int trilogy_connect(trilogy_conn_t *conn, const trilogy_sockopt_t *opts)
98
+ {
99
+ int rc = trilogy_connect_send(conn, opts);
100
+
101
+ if (rc < 0) {
102
+ return rc;
103
+ }
104
+
105
+ return trilogy_connect_handshake(conn);
106
+ }
107
+
108
+ int trilogy_connect_sock(trilogy_conn_t *conn, trilogy_sock_t *sock)
109
+ {
110
+ int rc = trilogy_connect_send_socket(conn, sock);
111
+
112
+ if (rc < 0) {
113
+ return rc;
114
+ }
115
+
116
+ return trilogy_connect_handshake(conn);
117
+ }
118
+
119
+ int trilogy_change_db(trilogy_conn_t *conn, const char *name, size_t name_len)
120
+ {
121
+ int rc = trilogy_change_db_send(conn, name, name_len);
122
+
123
+ if (rc == TRILOGY_AGAIN) {
124
+ rc = flush_full(conn);
125
+ }
126
+
127
+ if (rc < 0) {
128
+ return rc;
129
+ }
130
+
131
+ while (1) {
132
+ rc = trilogy_change_db_recv(conn);
133
+
134
+ if (rc != TRILOGY_AGAIN) {
135
+ return rc;
136
+ }
137
+
138
+ CHECKED(trilogy_sock_wait_read(conn->socket));
139
+ }
140
+ }
141
+
142
+ int trilogy_ping(trilogy_conn_t *conn)
143
+ {
144
+ int rc = trilogy_ping_send(conn);
145
+
146
+ if (rc == TRILOGY_AGAIN) {
147
+ rc = flush_full(conn);
148
+ }
149
+
150
+ if (rc < 0) {
151
+ return rc;
152
+ }
153
+
154
+ while (1) {
155
+ rc = trilogy_ping_recv(conn);
156
+
157
+ if (rc != TRILOGY_AGAIN) {
158
+ return rc;
159
+ }
160
+
161
+ CHECKED(trilogy_sock_wait_read(conn->socket));
162
+ }
163
+ }
164
+
165
+ int trilogy_query(trilogy_conn_t *conn, const char *query, size_t query_len, uint64_t *column_count_out)
166
+ {
167
+ int rc = trilogy_query_send(conn, query, query_len);
168
+
169
+ if (rc == TRILOGY_AGAIN) {
170
+ rc = flush_full(conn);
171
+ }
172
+
173
+ if (rc < 0) {
174
+ return rc;
175
+ }
176
+
177
+ while (1) {
178
+ rc = trilogy_query_recv(conn, column_count_out);
179
+
180
+ if (rc != TRILOGY_AGAIN) {
181
+ return rc;
182
+ }
183
+
184
+ CHECKED(trilogy_sock_wait_read(conn->socket));
185
+ }
186
+ }
187
+
188
+ int trilogy_read_full_column(trilogy_conn_t *conn, trilogy_column_t *column_out)
189
+ {
190
+ int rc;
191
+
192
+ while (1) {
193
+ rc = trilogy_read_column(conn, column_out);
194
+
195
+ if (rc != TRILOGY_AGAIN) {
196
+ return rc;
197
+ }
198
+
199
+ CHECKED(trilogy_sock_wait_read(conn->socket));
200
+ }
201
+ }
202
+
203
+ int trilogy_read_full_row(trilogy_conn_t *conn, trilogy_value_t *values_out)
204
+ {
205
+ int rc;
206
+
207
+ while (1) {
208
+ rc = trilogy_read_row(conn, values_out);
209
+
210
+ if (rc != TRILOGY_AGAIN) {
211
+ return rc;
212
+ }
213
+
214
+ CHECKED(trilogy_sock_wait_read(conn->socket));
215
+ }
216
+ }
217
+
218
+ int trilogy_close(trilogy_conn_t *conn)
219
+ {
220
+ int rc = trilogy_close_send(conn);
221
+
222
+ if (rc == TRILOGY_AGAIN) {
223
+ rc = flush_full(conn);
224
+ }
225
+
226
+ if (rc < 0) {
227
+ return rc;
228
+ }
229
+
230
+ while (1) {
231
+ rc = trilogy_close_recv(conn);
232
+
233
+ if (rc != TRILOGY_AGAIN) {
234
+ return rc;
235
+ }
236
+
237
+ CHECKED(trilogy_sock_wait_read(conn->socket));
238
+ }
239
+ }
240
+
241
+ #undef CHECKED