|
@ -34,9 +34,17 @@ from sabnzbd.constants import * |
|
|
import sabnzbd.config as config |
|
|
import sabnzbd.config as config |
|
|
import sabnzbd.cfg as cfg |
|
|
import sabnzbd.cfg as cfg |
|
|
import sabnzbd.bpsmeter as bpsmeter |
|
|
import sabnzbd.bpsmeter as bpsmeter |
|
|
|
|
|
import sabnzbd.scheduler |
|
|
import sabnzbd.nzbqueue |
|
|
import sabnzbd.nzbqueue |
|
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
|
|
#------------------------------------------------------------------------------ |
|
|
|
|
|
# Timeout penalty in minutes for each cause |
|
|
|
|
|
_PENALTY_UNKNOWN = 3 |
|
|
|
|
|
_PENALTY_502 = 5 |
|
|
|
|
|
_PENALTY_TIMEOUT = 10 |
|
|
|
|
|
_PENALTY_SHARE = 15 |
|
|
|
|
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
|
|
# Wrapper functions |
|
|
# Wrapper functions |
|
|
|
|
|
|
|
|
__DOWNLOADER = None # Global pointer to post-proc instance |
|
|
__DOWNLOADER = None # Global pointer to post-proc instance |
|
@ -175,6 +183,7 @@ class Server: |
|
|
self.busy_threads = [] |
|
|
self.busy_threads = [] |
|
|
self.idle_threads = [] |
|
|
self.idle_threads = [] |
|
|
self.active = True |
|
|
self.active = True |
|
|
|
|
|
self.bad_cons = 0 |
|
|
|
|
|
|
|
|
for i in range(threads): |
|
|
for i in range(threads): |
|
|
self.idle_threads.append(NewsWrapper(self, i+1)) |
|
|
self.idle_threads.append(NewsWrapper(self, i+1)) |
|
@ -241,6 +250,7 @@ class Downloader(Thread): |
|
|
""" Setup or re-setup single server |
|
|
""" Setup or re-setup single server |
|
|
When oldserver is defined and in use, delay startup. |
|
|
When oldserver is defined and in use, delay startup. |
|
|
Return True when newserver is primary |
|
|
Return True when newserver is primary |
|
|
|
|
|
Note that the server names are "host:port" strings! |
|
|
""" |
|
|
""" |
|
|
|
|
|
|
|
|
primary = False |
|
|
primary = False |
|
@ -342,6 +352,13 @@ class Downloader(Thread): |
|
|
self.__reset_nw(nw, "", warn=False) |
|
|
self.__reset_nw(nw, "", warn=False) |
|
|
else: |
|
|
else: |
|
|
self.__reset_nw(nw, "timed out") |
|
|
self.__reset_nw(nw, "timed out") |
|
|
|
|
|
server.bad_cons += 1 |
|
|
|
|
|
if server.optional and server.active and (server.bad_cons/server.threads) > 3: |
|
|
|
|
|
server.bad_cons = 0 |
|
|
|
|
|
server.active = False |
|
|
|
|
|
self.init_server(server.id, None) |
|
|
|
|
|
logging.warning('Server %s will be ignored for %s minutes', server.id, _PENALTY_TIMEOUT) |
|
|
|
|
|
sabnzbd.scheduler.plan_server(self.init_server, [None, server.id], _PENALTY_TIMEOUT) |
|
|
|
|
|
|
|
|
if server.restart: |
|
|
if server.restart: |
|
|
if not server.busy_threads: |
|
|
if not server.busy_threads: |
|
@ -519,6 +536,7 @@ class Downloader(Thread): |
|
|
except NNTPPermanentError, error: |
|
|
except NNTPPermanentError, error: |
|
|
# Handle login problems |
|
|
# Handle login problems |
|
|
block = False |
|
|
block = False |
|
|
|
|
|
penalty = 0 |
|
|
msg = error.response |
|
|
msg = error.response |
|
|
ecode = msg[:3] |
|
|
ecode = msg[:3] |
|
|
if ecode in ('481', '482', '381') or (ecode == '502' and clues_login(msg)): |
|
|
if ecode in ('481', '482', '381') or (ecode == '502' and clues_login(msg)): |
|
@ -531,19 +549,26 @@ class Downloader(Thread): |
|
|
logging.error('Too many connections to server %s:%s', server.host, server.port) |
|
|
logging.error('Too many connections to server %s:%s', server.host, server.port) |
|
|
self.__reset_nw(nw, None, warn=False, destroy=True) |
|
|
self.__reset_nw(nw, None, warn=False, destroy=True) |
|
|
server.threads -= 1 |
|
|
server.threads -= 1 |
|
|
|
|
|
elif (ecode == '502') and clues_too_many_ip(msg): |
|
|
|
|
|
# Account sharing? |
|
|
|
|
|
logging.info("Probable account sharing") |
|
|
|
|
|
penalty = _PENALTY_SHARE |
|
|
elif ecode == '502': |
|
|
elif ecode == '502': |
|
|
# Cannot connect (other reasons), block this server |
|
|
# Cannot connect (other reasons), block this server |
|
|
if server.active: |
|
|
if server.active: |
|
|
logging.error('Cannot connect to server %s:%s [%s]', server.host, server.port, msg) |
|
|
logging.warning('Cannot connect to server %s:%s [%s]', server.host, server.port, msg) |
|
|
block = True |
|
|
penalty = _PENALTY_502 |
|
|
else: |
|
|
else: |
|
|
# Unknown error, just keep trying |
|
|
# Unknown error, just keep trying |
|
|
# In the future we will give this server a penalty timeout |
|
|
|
|
|
logging.error('Cannot connect to server %s:%s [%s]', server.host, server.port, msg) |
|
|
logging.error('Cannot connect to server %s:%s [%s]', server.host, server.port, msg) |
|
|
if block: |
|
|
penalty = _PENALTY_UNKNOWN |
|
|
|
|
|
if block or (penalty and server.optional): |
|
|
if server.active: |
|
|
if server.active: |
|
|
server.active = False |
|
|
server.active = False |
|
|
self.init_server(server, None) |
|
|
self.init_server(server, None) |
|
|
|
|
|
if penalty and server.optional: |
|
|
|
|
|
logging.info('Server %s ignored for %s minutes', server.id, penalty) |
|
|
|
|
|
sabnzbd.scheduler.plan_server(self.init_server, [None, server.id], penalty) |
|
|
self.__reset_nw(nw, None, warn=False) |
|
|
self.__reset_nw(nw, None, warn=False) |
|
|
continue |
|
|
continue |
|
|
except: |
|
|
except: |
|
@ -688,3 +713,13 @@ def clues_too_many(text): |
|
|
if text.find(clue) >= 0: |
|
|
if text.find(clue) >= 0: |
|
|
return True |
|
|
return True |
|
|
return False |
|
|
return False |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def clues_too_many_ip(text): |
|
|
|
|
|
""" Check for any "account sharing" clues in the response code |
|
|
|
|
|
""" |
|
|
|
|
|
text = text.lower() |
|
|
|
|
|
for clue in ('simultaneous ip'): |
|
|
|
|
|
if text.find(clue) >= 0: |
|
|
|
|
|
return True |
|
|
|
|
|
return False |
|
|