lib/net/server.rb
def start
      # generate the first log messages
      LOG.info("%06d"%Process::pid) {"Starting RubyMTA at #{Time.now.strftime("%Y-%m-%d %H:%M:%S %Z")}, pid=#{Process::pid}"} if LOG
      LOG.info("%06d"%Process::pid) {"Options specified: #{ARGV.join(", ")}"} if LOG && ARGV.size>0

      # get the certificates, if any; they're needed for STARTTLS
      # we do this before daemonizing because the working folder might change
      $prv = if @options[:private_key] then OpenSSL::PKey::RSA.new File.read(@options[:private_key]) else nil end
      $crt = if @options[:certificate] then OpenSSL::X509::Certificate.new File.read(@options[:certificate]) else nil end

      # daemonize it if the option was set--it doesn't have to be root to daemonize it
      Process::daemon if @options[:daemon]

      # get the process ID and the user id AFTER demonizing, if that was requested
      pid = Process::pid
      uid = Process::Sys.getuid
      gid = Process::Sys.getgid
      
      LOG.info("%06d"%Process::pid) {"Daemonized at #{Time.now.strftime("%Y-%m-%d %H:%M:%S %Z")}, pid=#{pid}, uid=#{uid}, gid=#{gid}"} if LOG && @options[:daemon]

      # store the pid of the server session
      begin
        puts "RubyMTA running as PID=>#{pid}, UID=>#{uid}, GID=>#{gid}"
        File.open(@options[:pid_file],"w") { |f| f.write(pid.to_s) }
      rescue Errno::EACCES => e
        LOG.warn("%06d"%Process::pid) {"The pid couldn't be written. To save the pid, create a directory for '#{@options[:pid_file]}' with r/w permissions for this user."} if LOG
        LOG.warn("%06d"%Process::pid) {"Proceeding without writing the pid."} if LOG
      end

      # if ssltransportagent was started as root, make sure UserName and
      # GroupName have values because we have to drop root privileges
      # after we fork a process for the receiver
      if uid==0 # it's root
        if @options[:user_name].nil? || @options[:group_name].nil?
          LOG.error("%06d"%Process::pid) {"ssltransportagent can't be started as root unless UserName and GroupName are set."} if LOG
          exit(1)
        end
      end

      # this is the main loop which runs until admin enters ^C
      Signal.trap("INT") { raise ServerTerminate.new }
      Signal.trap("HUP") { restart if defined?(restart) }
      Signal.trap("CHLD") do
        begin
        Process.wait(-1, Process::WNOHANG)
        rescue Errno::ECHILD => e
          # ignore the error
        end
      end # trap-chld
      threads = []
      # start the server on multiple ports (the usual case)
      begin
        @options[:listening_ports].each do |port|
          threads << Thread.start(port) do |port|
            listening_thread(port)
          end
        end
        # the joins are done ONLY after all threads are started
        threads.each { |thread| thread.join }
      rescue ServerTerminate
        LOG.info("%06d"%Process::pid) {"#{@options[:server_name]} terminated by admin ^C"} if LOG
      end

      # attempt to remove the pid file
      begin
        File.delete(@options[:pid_file])
      rescue Errno::ENOENT => e
        LOG.warn("%06d"%Process::pid) {"No such file: #{e.inspect}"} if LOG
      rescue Errno::EACCES, Errno::EPERM
        LOG.warn("%06d"%Process::pid) {"Permission denied: #{e.inspect}"} if LOG
      end
    end
#
# This is the main setup and loop.
#
This is the main setup and loop.
This is the main setup and loop .
def start
      LOG.info("%06d"%Process::pid) {"Starting RubyMTA at #{Time.now.strftime("%Y-%m-%d %H:%M:%S %Z")}, pid=#{Process::pid}"} if LOG
      LOG.info("%06d"%Process::pid) {"Options specified: #{ARGV.join(", ")}"} if LOG && ARGV.size>0
      $prv = if @options[:private_key] then OpenSSL::PKey::RSA.new File.read(@options[:private_key]) else nil end
      $crt = if @options[:certificate] then OpenSSL::X509::Certificate.new File.read(@options[:certificate]) else nil end
      Process::daemon if @options[:daemon]
      pid = Process::pid
      uid = Process::Sys.getuid
      gid = Process::Sys.getgid
      LOG.info("%06d"%Process::pid) {"Daemonized at #{Time.now.strftime("%Y-%m-%d %H:%M:%S %Z")}, pid=#{pid}, uid=#{uid}, gid=#{gid}"} if LOG && @options[:daemon]
      begin
        puts "RubyMTA running as PID=>#{pid}, UID=>#{uid}, GID=>#{gid}"
        File.open(@options[:pid_file],"w") { |f| f.write(pid.to_s) }
      rescue Errno::EACCES => e
        LOG.warn("%06d"%Process::pid) {"The pid couldn't be written. To save the pid, create a directory for '#{@options[:pid_file]}' with r/w permissions for this user."} if LOG
        LOG.warn("%06d"%Process::pid) {"Proceeding without writing the pid."} if LOG
      end
      if uid==0 
        if @options[:user_name].nil? || @options[:group_name].nil?
          LOG.error("%06d"%Process::pid) {"ssltransportagent can't be started as root unless UserName and GroupName are set."} if LOG
          exit(1)
        end
      end
      Signal.trap("INT") { raise ServerTerminate.new }
      Signal.trap("HUP") { restart if defined?(restart) }
      Signal.trap("CHLD") do
        begin
        Process.wait(-1, Process::WNOHANG)
        rescue Errno::ECHILD => e
        end
      end 
      threads = []
      begin
        @options[:listening_ports].each do |port|
          threads << Thread.start(port) do |port|
            listening_thread(port)
          end
        end
        threads.each { |thread| thread.join }
      rescue ServerTerminate
        LOG.info("%06d"%Process::pid) {"#{@options[:server_name]} terminated by admin ^C"} if LOG
      end
      begin
        File.delete(@options[:pid_file])
      rescue Errno::ENOENT => e
        LOG.warn("%06d"%Process::pid) {"No such file: #{e.inspect}"} if LOG
      rescue Errno::EACCES, Errno::EPERM
        LOG.warn("%06d"%Process::pid) {"Permission denied: #{e.inspect}"} if LOG
      end
    end
def start LOG . info ( "%06d" % Process :: pid ) { "Starting RubyMTA at #{Time.now.strftime("%Y-%m-%d %H:%M:%S %Z")}, pid=#{Process::pid}" } if LOG LOG . info ( "%06d" % Process :: pid ) { "Options specified: #{ARGV.join(", ")}" } if LOG && ARGV . size > 0 $prv = if @options [ :private_key ] then OpenSSL :: PKey :: RSA . new File . read ( @options [ :private_key ] ) else nil end $crt = if @options [ :certificate ] then OpenSSL :: X509 :: Certificate . new File . read ( @options [ :certificate ] ) else nil end Process :: daemon if @options [ :daemon ] pid = Process :: pid uid = Process :: Sys . getuid gid = Process :: Sys . getgid LOG . info ( "%06d" % Process :: pid ) { "Daemonized at #{Time.now.strftime("%Y-%m-%d %H:%M:%S %Z")}, pid=#{pid}, uid=#{uid}, gid=#{gid}" } if LOG && @options [ :daemon ] begin puts "RubyMTA running as PID=>#{pid}, UID=>#{uid}, GID=>#{gid}" File . open ( @options [ :pid_file ] , "w" ) { | f | f . write ( pid . to_s ) } rescue Errno :: EACCES => e LOG . warn ( "%06d" % Process :: pid ) { "The pid couldn't be written. To save the pid, create a directory for '#{@options[:pid_file]}' with r/w permissions for this user." } if LOG LOG . warn ( "%06d" % Process :: pid ) { "Proceeding without writing the pid." } if LOG end if uid == 0 if @options [ :user_name ] . nil? || @options [ :group_name ] . nil? LOG . error ( "%06d" % Process :: pid ) { "ssltransportagent can't be started as root unless UserName and GroupName are set." } if LOG exit ( 1 ) end end Signal . trap ( "INT" ) { raise ServerTerminate . new } Signal . trap ( "HUP" ) { restart if defined? ( restart ) } Signal . trap ( "CHLD" ) do begin Process . wait ( - 1 , Process :: WNOHANG ) rescue Errno :: ECHILD => e end end threads = [ ] begin @options [ :listening_ports ] . each do | port | threads << Thread . start ( port ) do | port | listening_thread ( port ) end end threads . each { | thread | thread . join } rescue ServerTerminate LOG . info ( "%06d" % Process :: pid ) { "#{@options[:server_name]} terminated by admin ^C" } if LOG end begin File . delete ( @options [ :pid_file ] ) rescue Errno :: ENOENT => e LOG . warn ( "%06d" % Process :: pid ) { "No such file: #{e.inspect}" } if LOG rescue Errno :: EACCES , Errno :: EPERM LOG . warn ( "%06d" % Process :: pid ) { "Permission denied: #{e.inspect}" } if LOG end end
This is the main setup and loop.
This is the main setup and loop .
# generate the first log messages # get the certificates, if any; they're needed for STARTTLS # we do this before daemonizing because the working folder might change # daemonize it if the option was set--it doesn't have to be root to daemonize it # get the process ID and the user id AFTER demonizing, if that was requested # store the pid of the server session # if ssltransportagent was started as root, make sure UserName and # GroupName have values because we have to drop root privileges # after we fork a process for the receiver # it's root # this is the main loop which runs until admin enters ^C # ignore the error # trap-chld # start the server on multiple ports (the usual case) # the joins are done ONLY after all threads are started # attempt to remove the pid file