TCPSocket hangs after ctrl-c

Lähettäjä: Bjarke Bruun <bbj@swooplinux.org>
Aihe: Re: TCPSocket hangs after ctrl-c

>
> > I'm writing a small tcpserver and when I debug it and make changes
> I B> have to stop the server and I get a hanging socket
>
> What class do you use for your server : TCPServer ?

It's a small smtp server - just for fun... need to learn somethings
about ruby and implementing rfc 821 seems well cool for starters :slight_smile:

here is the core class (pre alpha everything you know :-))

I've tried the "kill -9" and it seems to work, but I would like it to be
done in code not on the CLI.

----
# Author: Bjarke Bruun, bbj@swooplinux.org
# Copyright: GPL version 2

require 'socket'
require 'config'

# Process the commandline parameters
$cli = CliInfo.new # don't mind this - it's just for setting some
variables on the CLI.

class Server
  def initialize
    @data = nil
    @f = File.new("rsmtp.log","a")
          ss = TCPServer.new '0.0.0.0', 10000
                server_going = true
                going = true
          while (@s = ss.accept) && server_going == true
      @f.puts("S: -> Client session established <-\n")
      fork {
        @s.print "220 Ruby SMTP Server/#{$cli.val("version")} \r\n"
                
        while going && @s.gets
          if $_ == "SERVER QUIT"
            # This is an attempt to send a "close" to the server so
            # it'll shut down proberly.
            server_going = false
            @s.close
            break
          end
          @f.puts("C: #{$_}")
          sleep 1
          r = cmd($_)
          @s.print r
          @f.puts("S: #{r}") if r != nil
          if r =~ /^354(.*)/
            r = getdata if r =~ /^354(.*)/
            @s.print r
            @f.puts("DEBUG > #{r}") if r != nil
          end
          if r =~ /^221(.*)/
            @f.puts("S: -> Quitting sesion successfully <- \n\n")
            @s.close
                              going = false
          end
                    end
                  @s.close
      }
          end
              @s.close
    @f.close
  end

  def getdata
    #puts "DEBUG: Receiving data"
    @data =
    while @s.gets !~ /^\./
      @data << $_
      @f.puts("\t#{@data[-1]}")
    end
    "250 message accepted\r\n"
  end
  
  def cmd line
          case line
      when /^HELO \[\d*.\d*.\d*.\d*\]/
        "250-#{$cli.val("SERVERNAME")} greets #{r}\r\n"
      when /^EHLO \[\d*.\d*.\d*.\d*\]/
        remote = line.split(/.\[/)
        "250 #{$cli.val("SERVERNAME")} greets
#{remote[1].split("\]")}"#250-8BITMIME\r\n250-SIZE\r\n250-DSN\r\n250
HELP"
      when /^MAIL FROM:(.*)/i
        @sndr = $1
        "250 OK\r\n" #: Sender okay\r\n"
      when /^RCPT TO:(.*)/i
        @rcpt = $1
        "250: Recipient okay\r\n"
      when /^DATA/i
        "354 Enter data, end with newline and '.'\r\n"
      when /^QUIT/i
        "221 closing connection\r\n"
      when /^RSET/i
        "250 okay\r\n"
    end
    end

  end

  # Run the server with logging enabled (it's a separate thread).
  server = Server.new

You do want to stop the program from the CLI but using a SIGTERM or
a SIGHUP rather than forcing a quit, right? I'd say it would be the
cleanest to trap the signal from your main process and then make sure
the child gets killed, too. Signal#trap and Process#abort should work
for that unless you want to set up a pipe/signal and bring the child
down more gracefully (in the event there's a read in progress).

Are you having problems with the SERVER QUIT command?

E

···

On Sunday 16 January 2005 15:27, ts wrote: