From: Sam Roberts Date: 2005-03-21T05:32:25+09:00 Subject: Re: can WEBrick bind to port 0, and then tell me what port was allocated? 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 ' 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] > [#, #] > [#, #, #, #] 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 ' 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 >