トップ «前の日記(2010-08-11) 最新 次の日記(2010-08-13)» 編集

ヨタの日々

2001|08|09|10|11|12|
2002|01|02|03|04|05|06|07|08|09|10|11|12|
2003|01|02|03|04|05|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|12|
2024|01|02|03|04|

2010-08-12 :-)

_ 朝ッ

0400 起床

_ ちゃりったー

朝日っておる

img_1252.jpg

img_1253.jpg

img_1254.jpg

img_1256.jpg

img_1257.jpg

img_1258.jpg

img_1261.jpg

img_1262.jpg

img_1264.jpg

img_1265.jpg

img_1267.jpg

_ [QuickML][コードリーディング][Ruby]QuickML を読む - server 起動

あとまわしにしていた server の処理を読む。起動のところだけ。

ファイルは lib/quickml/server.rb

Server クラスの処理。

   def initialize (config)
     @config = config
     @status = :stop
     @logger = @config.logger
     @server = TCPServer.new(@config.bind_address, @config.port)
   end

initialize() で内部の状態を設定などしている。server は Ruby の TCPServer をラップしている。

initialize() したら start() が呼ばれる。start() はこう。

   def start
     raise "server already started" if @status != :stop
     write_pid_file
     @logger.log sprintf("Server started at %s:%d [%d]",
                         "localhost", @config.port, Process.pid)
     accept
     @logger.log "Server exited [#{Process.pid}]"
     remove_pid_file
   end

状態をチェックし、起動済みならば例外を発生させる。

write_pid_file() では QuickML のプロセスID が書かれたファイルを作成している。Unix では伝統的な pid ファイルである。このファイルは quickml-ctl の stop() で以下のように使われる。

stop() {
        echo -n "Stopping QuickML services: "
        kill `cat /var/run/quickml.pid`
        echo
}

次に accept() する。名前の通り接続待ちになる。accept() はこう。

   def accept
     running_sessions = []
     @status = :running
     while @status == :running
       begin
         t = Thread.new(@server.accept) {|s|
           process_session(s)
         }
         t.abort_on_exception = true
         running_sessions.push(t)
       rescue Errno::ECONNABORTED # caused by @server.shutdown
       rescue Errno::EINVAL
       end
       running_sessions.delete_if {|t| t.status == false }
       if running_sessions.length >= @config.max_threads
         ThreadsWait.new(running_sessions).next_wait
       end
     end
     running_sessions.each {|t| t.join }
   end

実際の受け入れ処理は TCPServer の @server.accept がおこなっている。ブロックに渡される s は TCPSocket である。つまりソケット。

そして running_sessions には確立したセッションのスレッドが格納されていく。

セッションを処理している process_session() を見てみる。

   def process_session (socket)
     begin
       session = Session.new(@config, socket)
       session.start
     rescue Exception => e
       @logger.log "Unknown Session Error: #{e.class}: #{e.message}"
       @logger.log e.backtrace
     end
   end

Session を生成し、開始している。

Session はこう。

 class Session
   include GetText::GetText
   def initialize (config, socket)
     @socket = socket
     @config = config
     @command_table = [:helo, :ehlo, :noop, :quit, :rset, :rcpt, :mail, :data]
     @hello_host = "hello.host.invalid"
     @protocol = nil
     @peer_hostname = @socket.hostname
     @peer_address = @socket.address
     @remote_host = (@peer_hostname or @peer_address)
     @logger = @config.logger
     @catalog = @config.catalog
     @data_finished = false
     @my_hostname = if @config.port == 25 then
                      Socket.gethostname
                    else
                      "localhost"
                    end
     @message_charset = nil
   end

名前のとおり、接続ごとの処理を請け負う。

command_table に格納しているのは SMTP のコマンドである。

initialize() の次は start() である。

class Session
 :
    public
   def start
     start_time = Time.now
     _start
     elapsed = Time.now - start_time
     @logger.vlog "Session finished: #{elapsed} sec."
   end

_start() を見る。

class Session
 :
   def _start
     begin
       connect
       timeout(@config.timeout) {
         process
       }
     rescue TimeoutError
       @logger.vlog "Timeout: #{@remote_host}"
     ensure
       close
     end
   end

connect() して process() している。connect() を見る。

   def connect
     def @socket.puts(*objs)
       objs.each {|x|
         begin
           self.print x.xchomp, "\r\n"
         rescue Errno::EPIPE
         end
       }
     end
     @socket.puts "220 #{@my_hostname} ESMTP QuickML"
     @logger.vlog "Connect: #{@remote_host}"
   end

ここで、def @socket.puts(*objs) することによりこのスコープでのみ @socket の puts() をオーバーライドしている。*objs は渡された引数を表す。self.print で @socket.print を呼び出している。x には渡された引数、つまり文字列 String になる。xchomp() は lib/quickml/util.rb で定義している。

class String
 :
 def xchomp
    self.chomp("\n").chomp("\r")
  end
end

そしてさらに "\r\n" を追加している。つまり渡された文字列から \n \r を削除し、そのあとに \r\n を追加している。

のだと思う。

@socket がリモートから受け取った文字列に対して処理するならば分かるんだが、@socket.puts() はすぐ下の @socket.puts "220.... で使っているだけなのだろうけど、\r \n を削除するのはなぜなんだ。