First support for IPv6 and multiple interfaces

This commit is contained in:
René 'Necoro' Neumann 2011-02-08 19:27:00 +01:00
parent 9b535ba4b2
commit 396d7c3721
2 changed files with 60 additions and 10 deletions

View File

@ -38,6 +38,7 @@ arguments.
import os import os
import sys import sys
import optparse import optparse
import threading, signal
import radicale import radicale
@ -97,8 +98,40 @@ if options.daemon:
sys.exit() sys.exit()
sys.stdout = sys.stderr = open(os.devnull, "w") sys.stdout = sys.stderr = open(os.devnull, "w")
def exit (servers):
"""Cleanly shutdown all servers.
Might be called multiple times."""
for s in servers:
s.shutdown()
# Launch calendar server # Launch calendar server
server_class = radicale.HTTPSServer if options.ssl else radicale.HTTPServer server_class = radicale.HTTPSServer if options.ssl else radicale.HTTPServer
server = server_class( servers = []
(options.host, options.port), radicale.CalendarHTTPHandler) threads = []
server.serve_forever()
for host in (x.strip() for x in options.host.split(',')):
try:
server = server_class(
(host, options.port), radicale.CalendarHTTPHandler)
servers.append(server)
t = threading.Thread(target = server.serve_forever)
threads.append(t)
t.start()
except:
exit(servers)
raise
# clean exit on SIGTERM
signal.signal(signal.SIGTERM, lambda *a: exit(servers))
try:
while threads:
threads[0].join(1) # try one second
if threading.active_count() <= len(threads): # one thread died
break
except KeyboardInterrupt:
pass
finally:
exit(servers)

View File

@ -80,9 +80,24 @@ class HTTPServer(server.HTTPServer):
# Maybe a Pylint bug, ``__init__`` calls ``server.HTTPServer.__init__`` # Maybe a Pylint bug, ``__init__`` calls ``server.HTTPServer.__init__``
# pylint: disable=W0231 # pylint: disable=W0231
def __init__(self, address, handler): def __init__(self, address, handler, bind_and_activate = True):
"""Create server.""" """Create server."""
server.HTTPServer.__init__(self, address, handler) self.use_ipv6 = ':' in address[0]
if self.use_ipv6:
self.address_family = socket.AF_INET6
# call superclass, but do NOT bind and activate, as we might change socketopts
server.HTTPServer.__init__(self, address, handler, bind_and_activate = False)
if self.use_ipv6:
# only allow IPv6 connections to the IPv6 socket
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
if bind_and_activate:
self.server_bind()
self.server_activate()
self.acl = acl.load() self.acl = acl.load()
# pylint: enable=W0231 # pylint: enable=W0231
@ -91,22 +106,24 @@ class HTTPSServer(HTTPServer):
"""HTTPS server.""" """HTTPS server."""
PROTOCOL = "https" PROTOCOL = "https"
def __init__(self, address, handler): def __init__(self, address, handler, bind_and_activate = True):
"""Create server by wrapping HTTP socket in an SSL socket.""" """Create server by wrapping HTTP socket in an SSL socket."""
# Fails with Python 2.5, import if needed # Fails with Python 2.5, import if needed
# pylint: disable=F0401 # pylint: disable=F0401
import ssl import ssl
# pylint: enable=F0401 # pylint: enable=F0401
HTTPServer.__init__(self, address, handler) HTTPServer.__init__(self, address, handler, False)
self.socket = ssl.wrap_socket( self.socket = ssl.wrap_socket(
socket.socket(self.address_family, self.socket_type), self.socket, # we can use this, it is not bound yet
server_side=True, server_side=True,
certfile=config.get("server", "certificate"), certfile=config.get("server", "certificate"),
keyfile=config.get("server", "key"), keyfile=config.get("server", "key"),
ssl_version=ssl.PROTOCOL_SSLv23) ssl_version=ssl.PROTOCOL_SSLv23)
self.server_bind()
self.server_activate() if bind_and_activate:
self.server_bind()
self.server_activate()
class CalendarHTTPHandler(server.BaseHTTPRequestHandler): class CalendarHTTPHandler(server.BaseHTTPRequestHandler):