33# mailto:tommy@tmtm.org
44
55require "socket"
6- require "timeout"
76require "stringio"
87require "openssl"
98require_relative 'authenticator.rb'
@@ -511,20 +510,18 @@ def read
511510 data = ''
512511 len = nil
513512 begin
514- Timeout . timeout @opts [ :read_timeout ] do
515- header = @socket . read ( 4 )
516- raise EOFError unless header && header . length == 4
517- len1 , len2 , seq = header . unpack ( "CvC" )
518- len = ( len2 << 8 ) + len1
519- raise ProtocolError , "invalid packet: sequence number mismatch(#{ seq } != #{ @seq } (expected))" if @seq != seq
520- @seq = ( @seq + 1 ) % 256
521- ret = @socket . read ( len )
522- raise EOFError unless ret && ret . length == len
523- data . concat ret
524- end
513+ header = read_timeout ( 4 , @opts [ :read_timeout ] )
514+ raise EOFError unless header && header . length == 4
515+ len1 , len2 , seq = header . unpack ( "CvC" )
516+ len = ( len2 << 8 ) + len1
517+ raise ProtocolError , "invalid packet: sequence number mismatch(#{ seq } != #{ @seq } (expected))" if @seq != seq
518+ @seq = ( @seq + 1 ) % 256
519+ ret = read_timeout ( len , @opts [ :read_timeout ] )
520+ raise EOFError unless ret && ret . length == len
521+ data . concat ret
525522 rescue EOFError
526523 raise ClientError ::ServerGoneError , 'MySQL server has gone away'
527- rescue Timeout :: Error
524+ rescue Errno :: ETIMEDOUT
528525 raise ClientError , "read timeout"
529526 end while len == MAX_PACKET_LENGTH
530527
@@ -546,34 +543,73 @@ def read
546543 Packet . new ( data )
547544 end
548545
546+ def read_timeout ( len , timeout )
547+ return @socket . read ( len ) if timeout . nil? || timeout == 0
548+ result = ''
549+ e = ::Time . now + timeout
550+ while result . size < len
551+ now = ::Time . now
552+ raise Errno ::ETIMEDOUT if now > e
553+ r = @socket . read_nonblock ( len - result . size , exception : false )
554+ case r
555+ when :wait_readable
556+ IO . select ( [ @socket ] , nil , nil , e - now )
557+ next
558+ when :wait_writable
559+ IO . select ( nil , [ @socket ] , nil , e - now )
560+ next
561+ else
562+ result << r
563+ end
564+ end
565+ return result
566+ end
567+
549568 # Write one packet data
550569 # === Argument
551570 # data :: [String / IO] packet data. If data is nil, write empty packet.
552571 def write ( data )
553572 begin
554- Timeout . timeout @opts [ :write_timeout ] do
555- @socket . sync = false
556- if data . nil?
557- @socket . write [ 0 , 0 , @seq ] . pack ( "CvC" )
573+ @socket . sync = false
574+ if data . nil?
575+ write_timeout ( [ 0 , 0 , @seq ] . pack ( "CvC" ) , @opts [ :write_timeout ] )
576+ @seq = ( @seq + 1 ) % 256
577+ else
578+ data = StringIO . new data if data . is_a? String
579+ while d = data . read ( MAX_PACKET_LENGTH )
580+ write_timeout ( [ d . length %256 , d . length /256 , @seq ] . pack ( "CvC" ) +d , @opts [ :write_timeout ] )
558581 @seq = ( @seq + 1 ) % 256
559- else
560- data = StringIO . new data if data . is_a? String
561- while d = data . read ( MAX_PACKET_LENGTH )
562- @socket . write [ d . length %256 , d . length /256 , @seq ] . pack ( "CvC" )
563- @socket . write d
564- @seq = ( @seq + 1 ) % 256
565- end
566582 end
567- @socket . sync = true
568- @socket . flush
569583 end
584+ @socket . sync = true
585+ @socket . flush
570586 rescue Errno ::EPIPE
571587 raise ClientError ::ServerGoneError , 'MySQL server has gone away'
572- rescue Timeout :: Error
588+ rescue Errno :: ETIMEDOUT
573589 raise ClientError , "write timeout"
574590 end
575591 end
576592
593+ def write_timeout ( data , timeout )
594+ return @socket . write ( data ) if timeout . nil? || timeout == 0
595+ len = 0
596+ e = ::Time . now + timeout
597+ while len < data . size
598+ now = ::Time . now
599+ raise Errno ::ETIMEDOUT if now > e
600+ l = @socket . write_nonblock ( data [ len ..-1 ] , exception : false )
601+ case l
602+ when :wait_readable
603+ IO . select ( [ @socket ] , nil , nil , e - now )
604+ when :wait_writable
605+ IO . select ( nil , [ @socket ] , nil , e - now )
606+ else
607+ len += l
608+ end
609+ end
610+ return len
611+ end
612+
577613 # Read EOF packet
578614 # === Exception
579615 # [ProtocolError] packet is not EOF
0 commit comments