Index: fedd/Makefile/fedd.py
===================================================================
--- fedd/Makefile/fedd.py	(revision 88e7f2f76ed0f9ce0f3042e8d7ae0c319b72036b)
+++ fedd/Makefile/fedd.py	(revision 88e7f2f76ed0f9ce0f3042e8d7ae0c319b72036b)
@@ -0,0 +1,204 @@
+#!/usr/local/bin/python
+
+import os,sys
+
+from optparse import OptionParser
+
+from federation import config_parser
+from federation.server import server, xmlrpc_handler, soap_handler
+from federation.util import fedd_ssl_context
+from federation.deter_impl import new_feddservice
+
+from socket import error as socket_error
+from threading import Lock, Thread
+from signal import signal, pause, SIGINT, SIGTERM
+from select import select, error
+from time import sleep
+
+import logging
+import M2Crypto
+
+class fedd_opts(OptionParser):
+    """Encapsulate option processing in this class, rather than in main"""
+    def __init__(self):
+	OptionParser.__init__(self, usage="%prog [opts] (--help for details)",
+		version="0.1")
+
+	self.set_defaults(logfile=None, debug=0)
+
+	self.add_option("-d", "--debug", action="count", dest="debug", 
+		help="Set debug.  Repeat for more information")
+	self.add_option("-f", "--configfile", action="store",
+		default="/usr/local/etc/fedd.conf",
+		dest="configfile", help="Configuration file (required)")
+	self.add_option("-l", "--logfile", action="store", dest="logfile", 
+		help="File to send log messages to")
+	self.add_option("--trace", action="store_const", dest="tracefile", 
+		const=sys.stderr, help="Print SOAP exchange to stderr")
+
+servers_active = True	    # Sub-servers run while this is True
+servers = [ ]		    # server instances instantiated from services
+servers_lock = Lock()	    # Lock to manipulate servers from sub-server threads
+
+def shutdown(sig, frame):
+    """
+    On a signal, stop running sub-servers.  
+    
+    This is connected to signals below
+    """
+    global servers_active, flog
+
+    servers_active = False
+    flog.info("Received signal %d, shutting down" % sig);
+
+def run_server(s):
+    """
+    Operate a subserver, shutting down when servers_active is false.
+
+    Each server (that is host/port/transport triple) has a thread running this
+    function, so each can handle requests independently.  They all call in to
+    the same implementation, which must manage its own synchronization.
+    """
+    global servers_active   # Not strictly needed: servers_active is only read
+    global servers	    # List of active servers
+    global servers_lock	    # Lock to manipulate servers
+
+    while servers_active:
+	try:
+	    i, o, e = select((s,), (), (), 1.0)
+	    if s in i: s.handle_request()
+	except error:
+	    # The select call seems to get interrupted by signals as well as
+	    # the main thread.  This essentially ignores signals in this
+	    # thread.
+	    pass
+
+    # Done.  Remove us from the list
+    servers_lock.acquire()
+    servers.remove(s)
+    servers_lock.release()
+
+M2Crypto.threading.init()
+opts, args = fedd_opts().parse_args()
+
+# Logging setup
+flog = logging.getLogger("fedd")
+ffmt = logging.Formatter("%(asctime)s %(name)s %(message)s",
+	'%d %b %y %H:%M:%S')
+
+if opts.logfile: fh = logging.FileHandler(opts.logfile)
+else: fh = logging.StreamHandler(sys.stdout)
+
+# The handler will print anything, setting the logger level will affect what
+# gets recorded.
+fh.setLevel(logging.DEBUG)
+
+if opts.debug: flog.setLevel(logging.DEBUG)
+else: flog.setLevel(logging.INFO)
+
+fh.setFormatter(ffmt)
+flog.addHandler(fh)
+
+
+if not os.access(opts.configfile, os.R_OK):
+    sys.exit("Can't read config file %s" % opts.configfile)
+
+# Initialize the implementation
+try:
+    config= config_parser()
+    config.read(opts.configfile)
+except Exception, e:
+    sys.exit("Cannot parse config file %s: %s" % (opts.configfile, e))
+
+try:
+    impl = new_feddservice(config)
+except RuntimeError, e:
+    str = getattr(e, 'desc', None) or getattr(e,'message', None) or \
+	    "No message"
+    sys.exit("Error configuring fedd: %s" % str)
+
+if impl.cert_file:
+    if not os.access(impl.cert_file, os.R_OK):
+	sys.exit("Cannot read certificate file: %s" % impl.cert_file)
+else:
+    sys.exit("Must supply certificate file (probably in config)")
+
+if impl.trusted_certs:
+    if not os.access(impl.trusted_certs, os.R_OK):
+	sys.exit("Cannot read trusted certificate file: %s" % \
+		impl.trusted_certs)
+
+# Create the SSL credentials
+ctx = None
+while ctx == None:
+    try:
+	ctx = fedd_ssl_context(impl.cert_file, impl.trusted_certs, 
+		password=impl.cert_pwd)
+    except Exception, e:
+	if str(e) != "bad decrypt" or impl.cert_pwd != None:
+	    raise
+
+services = config.get("globals", "services", "23235")
+
+for s in services.split(","):
+    s = s.strip()
+    colons = s.count(":")
+    try:
+	if colons == 0:
+	    p = int(s)
+	    h = ''
+	    t = 'soap'
+	elif colons == 1:
+	    p, t  = s.split(":")
+	    p = int(p)
+	    h = ''
+	elif colons == 2:
+	    h, p, t  = s.split(":")
+	    p = int(p)
+	else:
+	    flog.error("Invalid service specification %s ignored." % s)
+	    continue
+    except ValueError:
+	flog.error("Error converting port to integer in %s: spec ignored" % s)
+	continue
+
+    t = t.lower()
+    sdebug = (opts.debug > 0)
+    try:
+	if t == 'soap':
+	    servers.append(server((h, p), soap_handler, ctx, impl, sdebug))
+	elif t == 'xmlrpc':
+	    servers.append(server((h, p), xmlrpc_handler, ctx, impl, sdebug))
+	else:
+	    flog.error("Invalid transport specification (%s) in service %s" % \
+		    (t, s))
+	    continue
+    except socket_error, e:
+	flog.error("Cannot create server for %s: %s" % (s, e[1]))
+	continue
+
+#  Make sure that there are no malformed servers in the list
+servers = [ s for s in servers if s ]
+
+# Catch signals
+signal(SIGINT, shutdown)
+signal(SIGTERM, shutdown)
+
+# Start the servers
+for s in servers:
+    Thread(target=run_server, args=(s,)).start()
+
+# Main thread waits for signals
+while servers_active:
+    sleep(1.0)
+
+#Once shutdown starts wait for all the servers to terminate.
+while True:
+    servers_lock.acquire()
+    if len(servers) == 0: 
+	servers_lock.release()
+	flog.info("All servers exited.  Terminating")
+	sys.exit(0)
+    servers_lock.release()
+    sleep(1)
+
