mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 17:12:13 -06:00
fix a handful of tftp crashes:
* if a nic was restarted mid-transfer, the server could crash * this workaround will probably fix a bunch of similar issues too * fix resource leak if dualstack fails the ipv4 bind
This commit is contained in:
parent
df7219d3b6
commit
d07859e8e6
|
@ -20,6 +20,7 @@ from .authsrv import VFS
|
||||||
from .bos import bos
|
from .bos import bos
|
||||||
from .util import (
|
from .util import (
|
||||||
Daemon,
|
Daemon,
|
||||||
|
ODict,
|
||||||
Pebkac,
|
Pebkac,
|
||||||
exclude_dotfiles,
|
exclude_dotfiles,
|
||||||
fsenc,
|
fsenc,
|
||||||
|
@ -545,6 +546,8 @@ class Ftpd(object):
|
||||||
if self.args.ftp4:
|
if self.args.ftp4:
|
||||||
ips = [x for x in ips if ":" not in x]
|
ips = [x for x in ips if ":" not in x]
|
||||||
|
|
||||||
|
ips = list(ODict.fromkeys(ips)) # dedup
|
||||||
|
|
||||||
ioloop = IOLoop()
|
ioloop = IOLoop()
|
||||||
for ip in ips:
|
for ip in ips:
|
||||||
for h, lp in hs:
|
for h, lp in hs:
|
||||||
|
|
|
@ -36,7 +36,7 @@ from partftpy.TftpShared import TftpException
|
||||||
from .__init__ import EXE, TYPE_CHECKING
|
from .__init__ import EXE, TYPE_CHECKING
|
||||||
from .authsrv import VFS
|
from .authsrv import VFS
|
||||||
from .bos import bos
|
from .bos import bos
|
||||||
from .util import BytesIO, Daemon, exclude_dotfiles, min_ex, runhook, undot
|
from .util import BytesIO, Daemon, ODict, exclude_dotfiles, min_ex, runhook, undot
|
||||||
|
|
||||||
if True: # pylint: disable=using-constant-test
|
if True: # pylint: disable=using-constant-test
|
||||||
from typing import Any, Union
|
from typing import Any, Union
|
||||||
|
@ -169,6 +169,8 @@ class Tftpd(object):
|
||||||
if self.args.ftp4:
|
if self.args.ftp4:
|
||||||
ips = [x for x in ips if ":" not in x]
|
ips = [x for x in ips if ":" not in x]
|
||||||
|
|
||||||
|
ips = list(ODict.fromkeys(ips)) # dedup
|
||||||
|
|
||||||
for ip in ips:
|
for ip in ips:
|
||||||
name = "tftp_%s" % (ip,)
|
name = "tftp_%s" % (ip,)
|
||||||
Daemon(self._start, name, [ip, ports])
|
Daemon(self._start, name, [ip, ports])
|
||||||
|
@ -179,18 +181,54 @@ class Tftpd(object):
|
||||||
|
|
||||||
def _start(self, ip, ports):
|
def _start(self, ip, ports):
|
||||||
fam = socket.AF_INET6 if ":" in ip else socket.AF_INET
|
fam = socket.AF_INET6 if ":" in ip else socket.AF_INET
|
||||||
srv = TftpServer.TftpServer("/", self._ls)
|
have_been_alive = False
|
||||||
with self.mutex:
|
while True:
|
||||||
self.srv.append(srv)
|
srv = TftpServer.TftpServer("/", self._ls)
|
||||||
self.ips.append(ip)
|
|
||||||
try:
|
|
||||||
srv.listen(ip, self.port, af_family=fam, ports=ports)
|
|
||||||
except OSError:
|
|
||||||
with self.mutex:
|
with self.mutex:
|
||||||
self.srv.remove(srv)
|
self.srv.append(srv)
|
||||||
self.ips.remove(ip)
|
self.ips.append(ip)
|
||||||
if ip != "0.0.0.0" or "::" not in self.ips:
|
|
||||||
raise
|
try:
|
||||||
|
# this is the listen loop; it should block forever
|
||||||
|
srv.listen(ip, self.port, af_family=fam, ports=ports)
|
||||||
|
except:
|
||||||
|
with self.mutex:
|
||||||
|
self.srv.remove(srv)
|
||||||
|
self.ips.remove(ip)
|
||||||
|
|
||||||
|
try:
|
||||||
|
srv.sock.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
bound = bool(srv.listenport)
|
||||||
|
except:
|
||||||
|
bound = False
|
||||||
|
|
||||||
|
if bound:
|
||||||
|
# this instance has managed to bind at least once
|
||||||
|
have_been_alive = True
|
||||||
|
|
||||||
|
if have_been_alive:
|
||||||
|
t = "tftp server [%s]:%d crashed; restarting in 3 sec:\n%s"
|
||||||
|
error(t, ip, self.port, min_ex())
|
||||||
|
time.sleep(3)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# server failed to start; could be due to dualstack (ipv6 managed to bind and this is ipv4)
|
||||||
|
if ip != "0.0.0.0" or "::" not in self.ips:
|
||||||
|
# nope, it's fatal
|
||||||
|
t = "tftp server [%s]:%d failed to start:\n%s"
|
||||||
|
error(t, ip, self.port, min_ex())
|
||||||
|
|
||||||
|
# yep; ignore
|
||||||
|
# (TODO: move the "listening @ ..." infolog in partftpy to
|
||||||
|
# after the bind attempt so it doesn't print twice)
|
||||||
|
return
|
||||||
|
|
||||||
|
info("tftp server [%s]:%d terminated", ip, self.port)
|
||||||
|
break
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
with self.mutex:
|
with self.mutex:
|
||||||
|
|
Loading…
Reference in a new issue