Thank you for your suggestions.

Quoting gotoyuzo / notwork.org, on Mon, Mar 21, 2005 at 04:46:10AM +0900:
> In message <20050320193414.GD911 / ensemble.local>,
>  `Sam Roberts <sroberts / uniserve.com>' wrote:
> > I don't create the socket, WEBrick does. I can't find a WEBrick API that
> > gives me back the socket, so I don't have a way to call
> > #getsockname on it to find the port.
> 
> > I also can't find a WEBrick API where I create the TCPSocket and pass it
> > in, that would work for me, too.
> 
> WEBrick::GenericServer#listen and #listeners may be useful.
> 
> % ruby -r webrick -e '
> s=WEBrick::HTTPServer.new(:Port=>0)
> p s.listeners
> s.listeners << TCPServer.new("127.0.0.1", "8080") # add a socket to listeners
> s.listen("127.0.0.1", 8081)                       # ditto.
> p s.listeners
> '
> [2005-03-21 04:43:58] INFO  WEBrick 1.3.1
> [2005-03-21 04:43:58] INFO  ruby 1.9.0 (2005-03-20) [i386-netbsd]
> [#<TCPServer:0x8314264>, #<TCPServer:0x83141c4>]
> [#<TCPServer:0x8314264>, #<TCPServer:0x83141c4>, #<TCPServer:0x8314048>, #<TCPServer:0x8313f08>]

If I set :Port=>0, every TCPServer gets a different port:

  w = WEBrick::HTTPServer.new(:Port=>0)
  w.listeners.each do |s| p Socket.unpack_sockaddr_in(s.getsockname) end
  [50101, "0.0.0.0"]
  [50102, "0.0.0.0"]

I don't want that, its unmanageable. And new listeners get added
dynamically, don't they?

Also, if I manually add a TCPServer with a specific port, I have the
same problem, new listeners will have a differerent port, I think.

Can I do something like this:

  w = WEBrick::HTTPServer.new(:Port=>0)
  s = w.listeners.first
  size = w.listeners.size - 1
  w.listeners.empty
  w.config[:Port] = s.addr[1]
  w.listeners << s
  size.times do
    w.listeners << TCPServer(w.config[:BindAddress], w.config[:Port])
  end

If I modify the config on the fly, will it be respected in the future,
all TCPServer sockets be on the same port after this?

Could I request that if :Port is zero (or perhaps :auto) that WEBrick do
this for me? It could create one server socket, determine the port,
reset :Port => the auto port, and then use it for new sockets.

This would allow me to do:

  w=WEBrick::HTTPServer.new(:Port=>:auto)

  s = DNSSD.register('my server', '_http._tcp', w.config[:Port])

What do you think?

Is there really a case when you would want every listener to have a
different port # assigned by the network stack? If not, maybe setting
:Port to 0 should have the above behaviour.

Quoting gotoyuzo / notwork.org, on Mon, Mar 21, 2005 at 04:36:12AM +0900:
> Hi,
> 
> In message <20050320184914.GB911 / ensemble.local>,
>  `Sam Roberts <sroberts / uniserve.com>' wrote:
> > INADDR_ANY with a port of zero. The system will select a free port.
> > 
> > Then, I can advertise that port using mDNS/DNS-SD.
> > 
> > Is this possible? I can maybe set :Port to 0, but I am searching the
> > webrick src and can't see a way to get the underlying socket up, so I
> > can ask it it's port.
> 
> Setting :Port to 0 works like you want. However WEBrick

Not exactly... :-)

> never report it. I think the log messages should be changed.
> How about the following patch?

Reporting it as a log message is a good idea, I like it.

For me, it doesn't really help because I need to know the port
programmatically, and I don't want to parse the log messages!

> 
> --- lib/webrick/server.rb	7 Mar 2005 12:32:07 -0000	1.9
> +++ lib/webrick/server.rb	20 Mar 2005 19:17:49 -0000
> @@ -74,11 +78,16 @@     def listen(address, port)
>  
>      def start(&block)
>        raise ServerError, "already started." if @status != :Stop
>        server_type = @config[:ServerType] || SimpleServer
>  
>        server_type.start{
> -        @logger.info \
> -          "#{self.class}#start: pid=#{$$} port=#{@config[:Port]}"
> +        @logger.info "#{self.class}#start: pid=#{$$}"
> +        @listeners.each{|sock|
> +          sockaddr = sock.addr
> +          addr = sockaddr[3]
> +          port = sockaddr[1]
> +          @logger.info "#{self.class}#start: addr=#{addr} port=#{port}"
> +        }
>          call_callback(:StartCallback)
>  
>          thgroup = ThreadGroup.new
> 
> -- 
> gotoyuzo
>