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):
allow_reuse_address = True
def serve_forever(self):
while state.shutdown == 0:
self.handle_request()

View File

@ -28,6 +28,7 @@ import ctypes
from struct import pack
from subprocess import call
from time import sleep
from random import randint
from api import MySimpleXMLRPCRequestHandler, StoppableXMLRPCServer
from helper_startup import isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections
@ -171,8 +172,25 @@ class singleAPI(threading.Thread, helper_threading.StoppableThread):
pass
def run(self):
se = StoppableXMLRPCServer((BMConfigParser().get('bitmessagesettings', 'apiinterface'), BMConfigParser().getint(
'bitmessagesettings', 'apiport')), MySimpleXMLRPCRequestHandler, True, True)
port = BMConfigParser().getint('bitmessagesettings', 'apiport')
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.serve_forever()

View File

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

View File

@ -119,7 +119,9 @@ class BMConnectionPool(object):
def startListening(self):
host = self.getListeningIP()
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):
if bind is None:

View File

@ -252,10 +252,29 @@ class TCPServer(AdvancedDispatcher):
AdvancedDispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
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.bound = True
self.listen(5)
def is_bound(self):
try:
return self.bound
except AttributeError:
return False
def handle_accept(self):
pair = self.accept()
if pair is not None:

View File

@ -7,6 +7,7 @@ from struct import unpack, pack
import threading
import time
from bmconfigparser import BMConfigParser
from network.connectionpool import BMConnectionPool
from helper_threading import *
import queues
import shared
@ -179,7 +180,6 @@ class uPnPThread(threading.Thread, StoppableThread):
def __init__ (self):
threading.Thread.__init__(self, name="uPnPThread")
self.localPort = BMConfigParser().getint('bitmessagesettings', 'port')
try:
self.extPort = BMConfigParser().getint('bitmessagesettings', 'extport')
except:
@ -199,6 +199,17 @@ class uPnPThread(threading.Thread, StoppableThread):
logger.debug("Starting UPnP thread")
logger.debug("Local IP: %s", self.localIP)
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'):
if time.time() - lastSent > self.sendSleep and len(self.routers) == 0:
try: