5 # Copyright (c) 1999-2005 Yukihiro Matsumoto
6 # Copyright (c) 1999-2005 Minero Aoki
8 # written and maintained by Minero Aoki <aamine@loveruby.net>
10 # This program is free software. You can re-distribute and/or
11 # modify this program under the same terms as Ruby itself,
12 # Ruby Distribute License or GNU General Public License.
14 # $Id: protocol.rb 11708 2007-02-12 23:01:19Z shyouhei $
17 # WARNING: This file is going to remove.
18 # Do not rely on the implementation written in this file.
26 class Protocol #:nodoc: internal use only
28 def Protocol.protocol_param(name, val)
29 module_eval(<<-End, __FILE__, __LINE__ + 1)
38 class ProtocolError < StandardError; end
39 class ProtoSyntaxError < ProtocolError; end
40 class ProtoFatalError < ProtocolError; end
41 class ProtoUnknownError < ProtocolError; end
42 class ProtoServerError < ProtocolError; end
43 class ProtoAuthError < ProtocolError; end
44 class ProtoCommandError < ProtocolError; end
45 class ProtoRetriableError < ProtocolError; end
46 ProtocRetryError = ProtoRetriableError
49 class BufferedIO #:nodoc: internal use only
58 attr_accessor :read_timeout
59 attr_accessor :debug_output
62 "#<#{self.class} io=#{@io}>"
79 def read(len, dest = '', ignore_eof = false)
80 LOG "reading #{len} bytes..."
83 while read_bytes + @rbuf.size < len
84 dest << (s = rbuf_consume(@rbuf.size))
88 dest << (s = rbuf_consume(len - read_bytes))
91 raise unless ignore_eof
93 LOG "read #{read_bytes} bytes"
97 def read_all(dest = '')
102 dest << (s = rbuf_consume(@rbuf.size))
109 LOG "read #{read_bytes} bytes"
113 def readuntil(terminator, ignore_eof = false)
115 until idx = @rbuf.index(terminator)
118 return rbuf_consume(idx + terminator.size)
120 raise unless ignore_eof
121 return rbuf_consume(@rbuf.size)
132 timeout(@read_timeout) {
133 @rbuf << @io.sysread(1024)
137 def rbuf_consume(len)
138 s = @rbuf.slice!(0, len)
139 @debug_output << %Q[-> #{s.dump}\n] if @debug_output
165 @debug_output << '<- ' if @debug_output
167 @debug_output << "\n" if @debug_output
168 bytes = @written_bytes
174 @debug_output << str.dump if @debug_output
176 @written_bytes += len
187 @save_debug_out = @debug_output
192 @debug_output = @save_debug_out
196 return unless @debug_output
197 @debug_output << msg + "\n"
202 class InternetMessageIO < BufferedIO #:nodoc: internal use only
203 def InternetMessageIO.old_open(addr, port,
204 open_timeout = nil, read_timeout = nil, debug_output = nil)
205 debug_output << "opening connection to #{addr}...\n" if debug_output
206 s = timeout(open_timeout) { TCPsocket.new(addr, port) }
208 io.read_timeout = read_timeout
209 io.debug_output = debug_output
222 def each_message_chunk
223 LOG 'reading message...'
226 while (line = readuntil("\r\n")) != ".\r\n"
227 read_bytes += line.size
228 yield line.sub(/\A\./, '')
231 LOG "read message (#{read_bytes} bytes)"
234 # *library private* (cannot handle 'break')
236 while (str = readuntil("\r\n")) != ".\r\n"
241 def write_message_0(src)
242 prev = @written_bytes
243 each_crlf_line(src) do |line|
244 write0 line.sub(/\A\./, '..')
246 @written_bytes - prev
253 def write_message(src)
254 LOG "writing message from #{src.class}"
257 using_each_crlf_line {
262 LOG "wrote #{len} bytes"
266 def write_message_by_block(&block)
267 LOG 'writing message from block'
270 using_each_crlf_line {
272 block.call(WriteAdapter.new(self, :write_message_0))
273 rescue LocalJumpError
274 # allow `break' from writer block
279 LOG "wrote #{len} bytes"
285 def using_each_crlf_line
288 if not @wbuf.empty? # unterminated last line
289 write0 @wbuf.chomp + "\r\n"
290 elsif @written_bytes == 0 # empty src
297 def each_crlf_line(src)
298 buffer_filling(@wbuf, src) do
299 while line = @wbuf.slice!(/\A.*(?:\n|\r\n|\r(?!\z))/n)
300 yield line.chomp("\n") + "\r\n"
305 def buffer_filling(buf, src)
307 when String # for speeding up.
308 0.step(src.size - 1, 1024) do |i|
312 when File # for speeding up.
313 while s = src.read(1024)
317 else # generic reader
320 yield if buf.size > 1024
322 yield unless buf.empty?
329 # The writer adapter class
332 def initialize(socket, method)
338 "#<#{self.class} socket=#{@socket.inspect}>"
342 @socket.__send__(@method_id, str)
353 write str.chomp("\n") + "\n"
362 class ReadAdapter #:nodoc: internal use only
363 def initialize(block)
372 call_block(str, &@block) if @block
377 # This method is needed because @block must be called by yield,
378 # not Proc#call. You can see difference when using `break' in
386 module NetPrivate #:nodoc: obsolete
387 Socket = ::Net::InternetMessageIO