trilogy 2.4.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,6 @@
1
1
  #include <netdb.h>
2
2
  #include <netinet/tcp.h>
3
+ #include <netinet/in.h>
3
4
  #include <poll.h>
4
5
  #include <sys/socket.h>
5
6
  #include <sys/types.h>
@@ -65,7 +66,11 @@ static ssize_t _cb_raw_read(trilogy_sock_t *_sock, void *buf, size_t nread)
65
66
  struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
66
67
  ssize_t data_read = read(sock->fd, buf, nread);
67
68
  if (data_read < 0) {
68
- return (ssize_t)TRILOGY_SYSERR;
69
+ if (errno == EINTR || errno == EAGAIN) {
70
+ return (ssize_t)TRILOGY_AGAIN;
71
+ } else {
72
+ return (ssize_t)TRILOGY_SYSERR;
73
+ }
69
74
  }
70
75
  return data_read;
71
76
  }
@@ -75,6 +80,14 @@ static ssize_t _cb_raw_write(trilogy_sock_t *_sock, const void *buf, size_t nwri
75
80
  struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
76
81
  ssize_t data_written = write(sock->fd, buf, nwrite);
77
82
  if (data_written < 0) {
83
+ if (errno == EINTR || errno == EAGAIN) {
84
+ return (ssize_t)TRILOGY_AGAIN;
85
+ }
86
+
87
+ if (errno == EPIPE) {
88
+ return (ssize_t)TRILOGY_CLOSED_CONNECTION;
89
+ }
90
+
78
91
  return (ssize_t)TRILOGY_SYSERR;
79
92
  }
80
93
  return data_written;
@@ -109,7 +122,53 @@ static int _cb_raw_close(trilogy_sock_t *_sock)
109
122
  return rc;
110
123
  }
111
124
 
112
- static int _cb_raw_shutdown(trilogy_sock_t *_sock) { return shutdown(trilogy_sock_fd(_sock), SHUT_RDWR); }
125
+ static int _cb_shutdown_connect(trilogy_sock_t *_sock) {
126
+ (void)_sock;
127
+ return TRILOGY_CLOSED_CONNECTION;
128
+ }
129
+ static ssize_t _cb_shutdown_write(trilogy_sock_t *_sock, const void *buf, size_t nwrite) {
130
+ (void)_sock;
131
+ (void)buf;
132
+ (void)nwrite;
133
+ return TRILOGY_CLOSED_CONNECTION;
134
+ }
135
+ static ssize_t _cb_shutdown_read(trilogy_sock_t *_sock, void *buf, size_t nread) {
136
+ (void)_sock;
137
+ (void)buf;
138
+ (void)nread;
139
+ return TRILOGY_CLOSED_CONNECTION;
140
+ }
141
+ static int _cb_shutdown_wait(trilogy_sock_t *_sock, trilogy_wait_t wait) {
142
+ (void)_sock;
143
+ (void)wait;
144
+ return TRILOGY_OK;
145
+ }
146
+ static int _cb_shutdown_shutdown(trilogy_sock_t *_sock) {
147
+ (void)_sock;
148
+ return TRILOGY_OK;
149
+ }
150
+
151
+ // Shutdown will close the underlying socket fd and replace all I/O operations with stubs which perform no action.
152
+ static int _cb_raw_shutdown(trilogy_sock_t *_sock) {
153
+ struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
154
+
155
+ // Replace all operations with stubs which return immediately
156
+ sock->base.connect_cb = _cb_shutdown_connect;
157
+ sock->base.read_cb = _cb_shutdown_read;
158
+ sock->base.write_cb = _cb_shutdown_write;
159
+ sock->base.wait_cb = _cb_shutdown_wait;
160
+ sock->base.shutdown_cb = _cb_shutdown_shutdown;
161
+
162
+ // These "raw" callbacks won't attempt further operations on the socket and work correctly with fd set to -1
163
+ sock->base.close_cb = _cb_raw_close;
164
+ sock->base.fd_cb = _cb_raw_fd;
165
+
166
+ if (sock->fd != -1)
167
+ close(sock->fd);
168
+ sock->fd = -1;
169
+
170
+ return TRILOGY_OK;
171
+ }
113
172
 
114
173
  static int set_nonblocking_fd(int sock)
115
174
  {
@@ -306,12 +365,18 @@ fail:
306
365
 
307
366
  static ssize_t ssl_io_return(struct trilogy_sock *sock, ssize_t ret)
308
367
  {
309
- if (ret < 0) {
368
+ if (ret <= 0) {
310
369
  int rc = SSL_get_error(sock->ssl, (int)ret);
311
370
  if (rc == SSL_ERROR_WANT_WRITE || rc == SSL_ERROR_WANT_READ) {
312
371
  return (ssize_t)TRILOGY_AGAIN;
313
- } else if (rc == SSL_ERROR_SYSCALL && errno != 0) {
314
- return (ssize_t)TRILOGY_SYSERR;
372
+ } else if (rc == SSL_ERROR_SYSCALL && !ERR_peek_error()) {
373
+ if (errno == 0) {
374
+ // On OpenSSL <= 1.1.1, SSL_ERROR_SYSCALL with an errno value
375
+ // of 0 indicates unexpected EOF from the peer.
376
+ return (ssize_t)TRILOGY_CLOSED_CONNECTION;
377
+ } else {
378
+ return (ssize_t)TRILOGY_SYSERR;
379
+ }
315
380
  }
316
381
  return (ssize_t)TRILOGY_OPENSSL_ERR;
317
382
  }
@@ -321,6 +386,11 @@ static ssize_t ssl_io_return(struct trilogy_sock *sock, ssize_t ret)
321
386
  static ssize_t _cb_ssl_read(trilogy_sock_t *_sock, void *buf, size_t nread)
322
387
  {
323
388
  struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
389
+
390
+ // This shouldn't be necessary, but protects against other libraries in the same process incorrectly leaving errors
391
+ // in the queue.
392
+ ERR_clear_error();
393
+
324
394
  ssize_t data_read = (ssize_t)SSL_read(sock->ssl, buf, (int)nread);
325
395
  return ssl_io_return(sock, data_read);
326
396
  }
@@ -328,6 +398,11 @@ static ssize_t _cb_ssl_read(trilogy_sock_t *_sock, void *buf, size_t nread)
328
398
  static ssize_t _cb_ssl_write(trilogy_sock_t *_sock, const void *buf, size_t nwrite)
329
399
  {
330
400
  struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
401
+
402
+ // This shouldn't be necessary, but protects against other libraries in the same process incorrectly leaving errors
403
+ // in the queue.
404
+ ERR_clear_error();
405
+
331
406
  ssize_t data_written = (ssize_t)SSL_write(sock->ssl, buf, (int)nwrite);
332
407
  return ssl_io_return(sock, data_written);
333
408
  }
@@ -340,15 +415,9 @@ static int _cb_ssl_shutdown(trilogy_sock_t *_sock)
340
415
  // we need to close it. The OpenSSL explicitly states
341
416
  // not to call SSL_shutdown on a broken SSL socket.
342
417
  SSL_free(sock->ssl);
343
- // Reset the handlers since we tore down SSL, so we
344
- // fall back to the regular methods for detecting
345
- // we have a closed connection and for the cleanup.
346
- sock->base.read_cb = _cb_raw_read;
347
- sock->base.write_cb = _cb_raw_write;
348
- sock->base.shutdown_cb = _cb_raw_shutdown;
349
- sock->base.close_cb = _cb_raw_close;
350
418
  sock->ssl = NULL;
351
419
 
420
+ // This will rewrite the handlers
352
421
  return _cb_raw_shutdown(_sock);
353
422
  }
354
423
 
@@ -356,7 +425,12 @@ static int _cb_ssl_close(trilogy_sock_t *_sock)
356
425
  {
357
426
  struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
358
427
  if (sock->ssl != NULL) {
359
- SSL_shutdown(sock->ssl);
428
+ if (SSL_in_init(sock->ssl) == 0) {
429
+ (void)SSL_shutdown(sock->ssl);
430
+ // SSL_shutdown might return WANT_WRITE or WANT_READ. Ideally we would retry but we don't want to block.
431
+ // It may also push an error onto the OpenSSL error queue, so clear that.
432
+ ERR_clear_error();
433
+ }
360
434
  SSL_free(sock->ssl);
361
435
  sock->ssl = NULL;
362
436
  }
@@ -537,6 +611,10 @@ int trilogy_sock_upgrade_ssl(trilogy_sock_t *_sock)
537
611
  {
538
612
  struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
539
613
 
614
+ // This shouldn't be necessary, but protects against other libraries in the same process incorrectly leaving errors
615
+ // in the queue.
616
+ ERR_clear_error();
617
+
540
618
  SSL_CTX *ctx = trilogy_ssl_ctx(&sock->base.opts);
541
619
 
542
620
  if (!ctx) {
@@ -548,7 +626,7 @@ int trilogy_sock_upgrade_ssl(trilogy_sock_t *_sock)
548
626
 
549
627
  if (sock->base.opts.ssl_mode == TRILOGY_SSL_VERIFY_IDENTITY && sock->base.opts.hostname == NULL) {
550
628
  // If hostname validation is requested and no hostname provided, treat it as an error.
551
- #if OPENSSL_VERSION_NUMBER >= 0x1010000fL
629
+ #ifdef SSL_F_TLS_PROCESS_SERVER_CERTIFICATE
552
630
  ERR_put_error(ERR_LIB_SSL, SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, SSL_R_CERTIFICATE_VERIFY_FAILED, NULL, 0);
553
631
  #else
554
632
  ERR_put_error(ERR_LIB_SSL, SSL_F_SSL3_GET_SERVER_CERTIFICATE, SSL_R_CERTIFICATE_VERIFY_FAILED, NULL, 0);
@@ -579,6 +657,10 @@ int trilogy_sock_upgrade_ssl(trilogy_sock_t *_sock)
579
657
  goto fail;
580
658
 
581
659
  for (;;) {
660
+ // This shouldn't be necessary, but protects against other libraries in the same process incorrectly leaving errors
661
+ // in the queue.
662
+ ERR_clear_error();
663
+
582
664
  int ret = SSL_connect(sock->ssl);
583
665
  if (ret == 1) {
584
666
  #if OPENSSL_VERSION_NUMBER < 0x1000200fL
@@ -621,28 +703,3 @@ fail:
621
703
  sock->ssl = NULL;
622
704
  return TRILOGY_OPENSSL_ERR;
623
705
  }
624
-
625
- int trilogy_sock_discard(trilogy_sock_t *_sock)
626
- {
627
- struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
628
-
629
- if (sock->fd < 0) {
630
- return TRILOGY_OK;
631
- }
632
-
633
- int null_fd = open("/dev/null", O_RDWR | O_CLOEXEC);
634
- if (null_fd < 0) {
635
- return TRILOGY_SYSERR;
636
- }
637
-
638
- if (dup2(null_fd, sock->fd) < 0) {
639
- close(null_fd);
640
- return TRILOGY_SYSERR;
641
- }
642
-
643
- if (close(null_fd) < 0) {
644
- return TRILOGY_SYSERR;
645
- }
646
-
647
- return TRILOGY_OK;
648
- }
@@ -0,0 +1,97 @@
1
+ class Trilogy
2
+ module Encoding
3
+ RUBY_ENCODINGS = {
4
+ "big5" => "Big5",
5
+ "dec8" => nil,
6
+ "cp850" => "CP850",
7
+ "hp8" => nil,
8
+ "koi8r" => "KOI8-R",
9
+ "latin1" => "ISO-8859-1",
10
+ "latin2" => "ISO-8859-2",
11
+ "swe7" => nil,
12
+ "ascii" => "US-ASCII",
13
+ "ujis" => "eucJP-ms",
14
+ "sjis" => "Shift_JIS",
15
+ "hebrew" => "ISO-8859-8",
16
+ "tis620" => "TIS-620",
17
+ "euckr" => "EUC-KR",
18
+ "koi8u" => "KOI8-R",
19
+ "gb2312" => "GB2312",
20
+ "greek" => "ISO-8859-7",
21
+ "cp1250" => "Windows-1250",
22
+ "gbk" => "GBK",
23
+ "latin5" => "ISO-8859-9",
24
+ "armscii8" => nil,
25
+ "utf8" => "UTF-8",
26
+ "ucs2" => "UTF-16BE",
27
+ "cp866" => "IBM866",
28
+ "keybcs2" => nil,
29
+ "macce" => "macCentEuro",
30
+ "macroman" => "macRoman",
31
+ "cp852" => "CP852",
32
+ "latin7" => "ISO-8859-13",
33
+ "utf8mb4" => "UTF-8",
34
+ "cp1251" => "Windows-1251",
35
+ "utf16" => "UTF-16",
36
+ "cp1256" => "Windows-1256",
37
+ "cp1257" => "Windows-1257",
38
+ "utf32" => "UTF-32",
39
+ "binary" => "ASCII-8BIT",
40
+ "geostd8" => nil,
41
+ "cp932" => "Windows-31J",
42
+ "eucjpms" => "eucJP-ms",
43
+ "utf16le" => "UTF-16LE",
44
+ "gb18030" => "GB18030",
45
+ }.freeze
46
+
47
+ CHARSETS = {
48
+ "big5" => CHARSET_BIG5_CHINESE_CI,
49
+ "cp850" => CHARSET_CP850_GENERAL_CI,
50
+ "koi8r" => CHARSET_KOI8R_GENERAL_CI,
51
+ "latin1" => CHARSET_LATIN1_GENERAL_CI,
52
+ "latin2" => CHARSET_LATIN2_GENERAL_CI,
53
+ "ascii" => CHARSET_ASCII_GENERAL_CI,
54
+ "ujis" => CHARSET_UJIS_JAPANESE_CI,
55
+ "sjis" => CHARSET_SJIS_JAPANESE_CI,
56
+ "hebrew" => CHARSET_HEBREW_GENERAL_CI,
57
+ "tis620" => CHARSET_TIS620_THAI_CI,
58
+ "euckr" => CHARSET_EUCKR_KOREAN_CI,
59
+ "koi8u" => CHARSET_KOI8U_GENERAL_CI,
60
+ "gb2312" => CHARSET_GB2312_CHINESE_CI,
61
+ "greek" => CHARSET_GREEK_GENERAL_CI,
62
+ "cp1250" => CHARSET_CP1250_GENERAL_CI,
63
+ "gbk" => CHARSET_GBK_CHINESE_CI,
64
+ "latin5" => CHARSET_LATIN5_TURKISH_CI,
65
+ "utf8" => CHARSET_UTF8_GENERAL_CI,
66
+ "ucs2" => CHARSET_UCS2_GENERAL_CI,
67
+ "cp866" => CHARSET_CP866_GENERAL_CI,
68
+ "cp932" => CHARSET_CP932_JAPANESE_CI,
69
+ "eucjpms" => CHARSET_EUCJPMS_JAPANESE_CI,
70
+ "utf16le" => CHARSET_UTF16_GENERAL_CI,
71
+ "gb18030" => CHARSET_GB18030_CHINESE_CI,
72
+ "macce" => CHARSET_MACCE_GENERAL_CI,
73
+ "macroman" => CHARSET_MACROMAN_GENERAL_CI,
74
+ "cp852" => CHARSET_CP852_GENERAL_CI,
75
+ "latin7" => CHARSET_LATIN7_GENERAL_CI,
76
+ "utf8mb4" => CHARSET_UTF8MB4_GENERAL_CI,
77
+ "cp1251" => CHARSET_CP1251_GENERAL_CI,
78
+ "utf16" => CHARSET_UTF16_GENERAL_CI,
79
+ "cp1256" => CHARSET_CP1256_GENERAL_CI,
80
+ "cp1257" => CHARSET_CP1257_GENERAL_CI,
81
+ "utf32" => CHARSET_UTF32_GENERAL_CI,
82
+ "binary" => CHARSET_BINARY,
83
+ }.freeze
84
+
85
+ def self.find(mysql_encoding)
86
+ unless rb_encoding = RUBY_ENCODINGS[mysql_encoding]
87
+ raise ArgumentError, "Unknown or unsupported encoding: #{mysql_encoding}"
88
+ end
89
+
90
+ ::Encoding.find(rb_encoding)
91
+ end
92
+
93
+ def self.charset(mysql_encoding)
94
+ CHARSETS[mysql_encoding]
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,118 @@
1
+ class Trilogy
2
+ # Trilogy::Error is the base error type. All errors raised by Trilogy
3
+ # should be descendants of Trilogy::Error
4
+ module Error
5
+ attr_reader :error_code
6
+ end
7
+
8
+ # Trilogy::ConnectionError is the base error type for all potentially transient
9
+ # network errors.
10
+ module ConnectionError
11
+ include Error
12
+ end
13
+
14
+ # Trilogy may raise various syscall errors, which we treat as Trilogy::Errors.
15
+ class SyscallError
16
+ ERRORS = {}
17
+
18
+ Errno.constants
19
+ .map { |c| Errno.const_get(c) }.uniq
20
+ .select { |c| c.is_a?(Class) && c < SystemCallError }
21
+ .each do |c|
22
+ errno_name = c.to_s.split('::').last
23
+ ERRORS[c::Errno] = const_set(errno_name, Class.new(c) { include Trilogy::Error })
24
+ end
25
+
26
+ ERRORS.freeze
27
+
28
+ class << self
29
+ def from_errno(errno, message)
30
+ ERRORS[errno].new(message)
31
+ end
32
+ end
33
+ end
34
+
35
+ class BaseError < StandardError
36
+ include Error
37
+
38
+ def initialize(error_message = nil, error_code = nil)
39
+ message = error_code ? "#{error_code}: #{error_message}" : error_message
40
+ super(message)
41
+ @error_code = error_code
42
+ end
43
+ end
44
+
45
+ class BaseConnectionError < BaseError
46
+ include ConnectionError
47
+ end
48
+
49
+ # Trilogy::ClientError is the base error type for invalid queries or parameters
50
+ # that shouldn't be retried.
51
+ class ClientError < BaseError
52
+ include Error
53
+ end
54
+
55
+ class QueryError < ClientError
56
+ end
57
+
58
+ class CastError < ClientError
59
+ end
60
+
61
+ class TimeoutError < Errno::ETIMEDOUT
62
+ include ConnectionError
63
+
64
+ def initialize(error_message = nil, error_code = nil)
65
+ super
66
+ @error_code = error_code
67
+ end
68
+ end
69
+
70
+ class ConnectionRefusedError < Errno::ECONNREFUSED
71
+ include ConnectionError
72
+ end
73
+
74
+ class ConnectionResetError < Errno::ECONNRESET
75
+ include ConnectionError
76
+ end
77
+
78
+ # DatabaseError was replaced by ProtocolError, but we'll keep it around as an
79
+ # ancestor of ProtocolError for compatibility reasons (e.g. so `rescue DatabaseError`
80
+ # still works. We can remove this class in the next major release.
81
+ module DatabaseError
82
+ end
83
+
84
+ class ProtocolError < BaseError
85
+ include DatabaseError
86
+
87
+ ERROR_CODES = {
88
+ 1205 => TimeoutError, # ER_LOCK_WAIT_TIMEOUT
89
+ 1044 => BaseConnectionError, # ER_DBACCESS_DENIED_ERROR
90
+ 1045 => BaseConnectionError, # ER_ACCESS_DENIED_ERROR
91
+ 1064 => QueryError, # ER_PARSE_ERROR
92
+ 1152 => BaseConnectionError, # ER_ABORTING_CONNECTION
93
+ 1153 => BaseConnectionError, # ER_NET_PACKET_TOO_LARGE
94
+ 1154 => BaseConnectionError, # ER_NET_READ_ERROR_FROM_PIPE
95
+ 1155 => BaseConnectionError, # ER_NET_FCNTL_ERROR
96
+ 1156 => BaseConnectionError, # ER_NET_PACKETS_OUT_OF_ORDER
97
+ 1157 => BaseConnectionError, # ER_NET_UNCOMPRESS_ERROR
98
+ 1158 => BaseConnectionError, # ER_NET_READ_ERROR
99
+ 1159 => BaseConnectionError, # ER_NET_READ_INTERRUPTED
100
+ 1160 => BaseConnectionError, # ER_NET_ERROR_ON_WRITE
101
+ 1161 => BaseConnectionError, # ER_NET_WRITE_INTERRUPTED
102
+ 1927 => BaseConnectionError, # ER_CONNECTION_KILLED
103
+ }
104
+ class << self
105
+ def from_code(message, code)
106
+ ERROR_CODES.fetch(code, self).new(message, code)
107
+ end
108
+ end
109
+ end
110
+
111
+ class SSLError < BaseError
112
+ include ConnectionError
113
+ end
114
+
115
+ class ConnectionClosed < IOError
116
+ include ConnectionError
117
+ end
118
+ end
@@ -0,0 +1,33 @@
1
+ class Trilogy
2
+ class Result
3
+ attr_reader :fields, :rows, :query_time, :affected_rows, :last_insert_id
4
+
5
+ def count
6
+ rows.count
7
+ end
8
+
9
+ def each_hash
10
+ return enum_for(:each_hash) unless block_given?
11
+
12
+ rows.each do |row|
13
+ this_row = {}
14
+
15
+ idx = 0
16
+ row.each do |col|
17
+ this_row[fields[idx]] = col
18
+ idx += 1
19
+ end
20
+
21
+ yield this_row
22
+ end
23
+
24
+ self
25
+ end
26
+
27
+ def each(&bk)
28
+ rows.each(&bk)
29
+ end
30
+
31
+ include Enumerable
32
+ end
33
+ end
@@ -1,3 +1,3 @@
1
1
  class Trilogy
2
- VERSION = "2.4.0"
2
+ VERSION = "2.5.0"
3
3
  end