Try new ports of binding fails

- API and BM protocol will try random ports for binding if those
configured are occupied
This commit is contained in:
Peter Šurda 2017-08-09 17:29:23 +02:00
parent 0324958e92
commit cc955cd69d
Signed by untrusted user: PeterSurda
GPG Key ID: 0C5F50C0B5F37D87
6 changed files with 62 additions and 5 deletions

View File

@ -55,6 +55,8 @@ class APIError(Exception):
class StoppableXMLRPCServer(SimpleXMLRPCServer): class StoppableXMLRPCServer(SimpleXMLRPCServer):
allow_reuse_address = True
def serve_forever(self): def serve_forever(self):
while state.shutdown == 0: while state.shutdown == 0:
self.handle_request() self.handle_request()

View File

@ -28,6 +28,7 @@ import ctypes
from struct import pack from struct import pack
from subprocess import call from subprocess import call
from time import sleep from time import sleep
from random import randint
from api import MySimpleXMLRPCRequestHandler, StoppableXMLRPCServer from api import MySimpleXMLRPCRequestHandler, StoppableXMLRPCServer
from helper_startup import isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections from helper_startup import isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections
@ -171,8 +172,25 @@ class singleAPI(threading.Thread, helper_threading.StoppableThread):
pass pass
def run(self): def run(self):
se = StoppableXMLRPCServer((BMConfigParser().get('bitmessagesettings', 'apiinterface'), BMConfigParser().getint( port = BMConfigParser().getint('bitmessagesettings', 'apiport')
'bitmessagesettings', 'apiport')), MySimpleXMLRPCRequestHandler, True, True) try:
from errno import WSAEADDRINUSE
except (ImportError, AttributeError):
errno.WSAEADDRINUSE = errno.EADDRINUSE
for attempt in range(50):
try:
if attempt > 0:
port = randint(32767, 65535)
se = StoppableXMLRPCServer((BMConfigParser().get('bitmessagesettings', 'apiinterface'), port),
MySimpleXMLRPCRequestHandler, True, True)
except socket.error as e:
if e.errno in (errno.EADDRINUSE, errno.WSAEADDRINUSE):
continue
else:
if attempt > 0:
BMConfigParser().set("bitmessagesettings", "apiport", str(port))
BMConfigParser().save()
break
se.register_introspection_functions() se.register_introspection_functions()
se.serve_forever() se.serve_forever()

View File

@ -58,6 +58,7 @@ import os
from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \ from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \
ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \ ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \
ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ENOTSOCK, EINTR, ETIMEDOUT, \ ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ENOTSOCK, EINTR, ETIMEDOUT, \
EADDRINUSE, \
errorcode errorcode
try: try:
from errno import WSAEWOULDBLOCK from errno import WSAEWOULDBLOCK
@ -71,6 +72,10 @@ try:
from errno import WSAECONNRESET from errno import WSAECONNRESET
except (ImportError, AttributeError): except (ImportError, AttributeError):
WSAECONNRESET = ECONNRESET WSAECONNRESET = ECONNRESET
try:
from errno import WSAEADDRINUSE
except (ImportError, AttributeError):
WSAEADDRINUSE = EADDRINUSE
_DISCONNECTED = frozenset((ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, _DISCONNECTED = frozenset((ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE,
EBADF, ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ETIMEDOUT, EBADF, ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ETIMEDOUT,

View File

@ -119,7 +119,9 @@ class BMConnectionPool(object):
def startListening(self): def startListening(self):
host = self.getListeningIP() host = self.getListeningIP()
port = BMConfigParser().safeGetInt("bitmessagesettings", "port") port = BMConfigParser().safeGetInt("bitmessagesettings", "port")
self.listeningSockets[state.Peer(host, port)] = network.tcp.TCPServer(host=host, port=port) # correct port even if it changed
ls = network.tcp.TCPServer(host=host, port=port)
self.listeningSockets[ls.destination] = ls
def startUDPSocket(self, bind=None): def startUDPSocket(self, bind=None):
if bind is None: if bind is None:

View File

@ -252,10 +252,29 @@ class TCPServer(AdvancedDispatcher):
AdvancedDispatcher.__init__(self) AdvancedDispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr() self.set_reuse_addr()
self.bind((host, port)) for attempt in range(50):
try:
if attempt > 0:
port = random.randint(32767, 65535)
self.bind((host, port))
except socket.error as e:
if e.errno in (asyncore.EADDRINUSE, asyncore.WSAEADDRINUSE):
continue
else:
if attempt > 0:
BMConfigParser().set("bitmessagesettings", "port", str(port))
BMConfigParser().save()
break
self.destination = state.Peer(host, port) self.destination = state.Peer(host, port)
self.bound = True
self.listen(5) self.listen(5)
def is_bound(self):
try:
return self.bound
except AttributeError:
return False
def handle_accept(self): def handle_accept(self):
pair = self.accept() pair = self.accept()
if pair is not None: if pair is not None:

View File

@ -7,6 +7,7 @@ from struct import unpack, pack
import threading import threading
import time import time
from bmconfigparser import BMConfigParser from bmconfigparser import BMConfigParser
from network.connectionpool import BMConnectionPool
from helper_threading import * from helper_threading import *
import queues import queues
import shared import shared
@ -179,7 +180,6 @@ class uPnPThread(threading.Thread, StoppableThread):
def __init__ (self): def __init__ (self):
threading.Thread.__init__(self, name="uPnPThread") threading.Thread.__init__(self, name="uPnPThread")
self.localPort = BMConfigParser().getint('bitmessagesettings', 'port')
try: try:
self.extPort = BMConfigParser().getint('bitmessagesettings', 'extport') self.extPort = BMConfigParser().getint('bitmessagesettings', 'extport')
except: except:
@ -199,6 +199,17 @@ class uPnPThread(threading.Thread, StoppableThread):
logger.debug("Starting UPnP thread") logger.debug("Starting UPnP thread")
logger.debug("Local IP: %s", self.localIP) logger.debug("Local IP: %s", self.localIP)
lastSent = 0 lastSent = 0
# wait until asyncore binds so that we know the listening port
bound = False
while state.shutdown == 0 and not self._stopped and not bound:
for s in BMConnectionPool().listeningSockets.values():
if s.is_bound():
bound = True
if not bound:
time.sleep(1)
self.localPort = BMConfigParser().getint('bitmessagesettings', 'port')
while state.shutdown == 0 and BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'): while state.shutdown == 0 and BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'):
if time.time() - lastSent > self.sendSleep and len(self.routers) == 0: if time.time() - lastSent > self.sendSleep and len(self.routers) == 0:
try: try: