diff --git a/docs/topics/settings.rst b/docs/topics/settings.rst index 642348b0e..59a6c348d 100644 --- a/docs/topics/settings.rst +++ b/docs/topics/settings.rst @@ -962,9 +962,9 @@ will be enabled (provided its extension is also enabled). TELNETCONSOLE_PORT ------------------ -Default: ``6023`` +Default: ``[6023, 6073]`` -The port to use for the telnet console. If set to ``None`` or ``0``, a +The port range to use for the telnet console. If set to ``None`` or ``0``, a dynamically assigned port is used. For more info see :ref:`topics-telnetconsole`. diff --git a/docs/topics/webservice.rst b/docs/topics/webservice.rst index 87717cfc9..b15db661b 100644 --- a/docs/topics/webservice.rst +++ b/docs/topics/webservice.rst @@ -131,10 +131,10 @@ the log is sent to standard scrapy log. WEBSERVICE_PORT --------------- -Default: ``6080`` +Default: ``[6080, 7030]`` -The port to use for the web service. If set to ``None`` or ``0``, a dynamically -assigned port is used. +The port range to use for the web service. If set to ``None`` or ``0``, a +dynamically assigned port is used. WEBSERVICE_RESOURCES -------------------- diff --git a/scrapy/conf/default_settings.py b/scrapy/conf/default_settings.py index 696420034..2be98bd7a 100644 --- a/scrapy/conf/default_settings.py +++ b/scrapy/conf/default_settings.py @@ -251,11 +251,11 @@ URLLENGTH_LIMIT = 2083 USER_AGENT = '%s/%s' % (BOT_NAME, BOT_VERSION) TELNETCONSOLE_ENABLED = 1 -TELNETCONSOLE_PORT = 6023 # if None, uses a dynamic port +TELNETCONSOLE_PORT = [6023, 6073] WEBSERVICE_ENABLED = True WEBSERVICE_LOGFILE = None -WEBSERVICE_PORT = 6080 +WEBSERVICE_PORT = [6080, 7030] WEBSERVICE_RESOURCES = {} WEBSERVICE_RESOURCES_BASE = { 'scrapy.contrib.webservice.crawler.CrawlerResource': 1, diff --git a/scrapy/telnet.py b/scrapy/telnet.py index 41b17ac74..1d9d9e1b0 100644 --- a/scrapy/telnet.py +++ b/scrapy/telnet.py @@ -8,16 +8,17 @@ import pprint from twisted.conch import manhole, telnet from twisted.conch.insults import insults -from twisted.internet import reactor, protocol +from twisted.internet import protocol from scrapy.xlib.pydispatch import dispatcher from scrapy.exceptions import NotConfigured from scrapy.project import crawler from scrapy.stats import stats -from scrapy import signals +from scrapy import log, signals from scrapy.utils.signal import send_catch_log from scrapy.utils.trackref import print_live_refs from scrapy.utils.engine import print_engine_status +from scrapy.utils.reactor import listen_tcp from scrapy.conf import settings try: @@ -37,12 +38,14 @@ class TelnetConsole(protocol.ServerFactory): if not settings.getbool('TELNETCONSOLE_ENABLED'): raise NotConfigured self.noisy = False - self.portnum = settings.getint('TELNETCONSOLE_PORT') + self.portrange = map(int, settings.getlist('TELNETCONSOLE_PORT')) dispatcher.connect(self.start_listening, signals.engine_started) dispatcher.connect(self.stop_listening, signals.engine_stopped) def start_listening(self): - self.port = reactor.listenTCP(self.portnum, self) + self.port = listen_tcp(self.portrange, self) + log.msg("Telnet console listening on port %d" % self.port.getHost().port, + log.DEBUG) def stop_listening(self): self.port.stopListening() diff --git a/scrapy/utils/reactor.py b/scrapy/utils/reactor.py new file mode 100644 index 000000000..3d1e145b5 --- /dev/null +++ b/scrapy/utils/reactor.py @@ -0,0 +1,15 @@ +from twisted.internet import reactor, error + +def listen_tcp(portrange, factory): + """Like reactor.listenTCP but tries different ports in a range.""" + assert len(portrange) in [1, 2], "invalid portrange: %s" % portrange + if not hasattr(portrange, '__iter__'): + return reactor.listenTCP(portrange, factory) + if len(portrange) == 1: + return reactor.listenTCP(portrange[0], factory) + for x in range(portrange[0], portrange[1]+1): + try: + return reactor.listenTCP(x, factory) + except error.CannotListenError: + if x == portrange[1]: + raise diff --git a/scrapy/webservice.py b/scrapy/webservice.py index 7559656b4..8ab6513e0 100644 --- a/scrapy/webservice.py +++ b/scrapy/webservice.py @@ -1,19 +1,19 @@ """ Scrapy web services extension -See docs/topics/ws.rst +See docs/topics/webservice.rst """ -from twisted.internet import reactor from twisted.web import server, error from scrapy.xlib.pydispatch import dispatcher from scrapy.exceptions import NotConfigured -from scrapy import signals +from scrapy import log, signals from scrapy.utils.jsonrpc import jsonrpc_server_call from scrapy.utils.serialize import ScrapyJSONEncoder, ScrapyJSONDecoder from scrapy.utils.misc import load_object from scrapy.utils.txweb import JsonResource as JsonResource_ +from scrapy.utils.reactor import listen_tcp from scrapy.utils.conf import build_component_list from scrapy.conf import settings @@ -67,7 +67,7 @@ class WebService(server.Site): if not settings.getbool('WEBSERVICE_ENABLED'): raise NotConfigured logfile = settings['WEBSERVICE_LOGFILE'] - self.portnum = settings.getint('WEBSERVICE_PORT') + self.portrange = map(int, settings.getlist('WEBSERVICE_PORT')) root = RootResource() reslist = build_component_list(settings['WEBSERVICE_RESOURCES_BASE'], \ settings['WEBSERVICE_RESOURCES']) @@ -80,7 +80,9 @@ class WebService(server.Site): dispatcher.connect(self.stop_listening, signals.engine_stopped) def start_listening(self): - self.port = reactor.listenTCP(self.portnum, self) + self.port = listen_tcp(self.portrange, self) + log.msg("Web service listening on port %d" % self.port.getHost().port, + log.DEBUG) def stop_listening(self): self.port.stopListening()