-##
-# This module implements a general-purpose server layer for sfa.
-# The same basic server should be usable on the registry, component, or
-# other interfaces.
-#
-# TODO: investigate ways to combine this with existing PLC server?
-##
-
-import threading
-import socket
-import SimpleXMLRPCServer
-
-from sfa.util.sfalogging import logger
-from sfa.trust.certificate import Keypair, Certificate
-from sfa.plc.api import PlcComponentApi
-from sfa.server.threadedserver import ThreadedServer
-
-
-##
-# taken from the web (XXX find reference). Implents HTTPS xmlrpc request handler
-
-class SecureXMLRpcRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
- """Secure XML-RPC request handler class.
-
- It it very similar to SimpleXMLRPCRequestHandler but it uses HTTPS for transporting XML data.
- """
- def setup(self):
- self.connection = self.request
- self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
- self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
-
- def do_POST(self):
- """Handles the HTTPS POST request.
-
- It was copied out from SimpleXMLRPCServer.py and modified to shutdown the socket cleanly.
- """
- try:
- peer_cert = Certificate()
- peer_cert.load_from_pyopenssl_x509(self.connection.get_peer_certificate())
- self.api = PlcComponentApi(peer_cert = peer_cert,
- interface = self.server.interface,
- key_file = self.server.key_file,
- cert_file = self.server.cert_file)
- # get arguments
- request = self.rfile.read(int(self.headers["content-length"]))
- # In previous versions of SimpleXMLRPCServer, _dispatch
- # could be overridden in this class, instead of in
- # SimpleXMLRPCDispatcher. To maintain backwards compatibility,
- # check to see if a subclass implements _dispatch and dispatch
- # using that method if present.
- #response = self.server._marshaled_dispatch(request, getattr(self, '_dispatch', None))
- # XX TODO: Need to get the real remote address
- remote_addr = (remote_ip, remote_port) = self.connection.getpeername()
- self.api.remote_addr = remote_addr
- #remote_addr = (self.rfile.connection.remote_ip, remote_port)
- #self.api.remote_addr = remote_addr
- response = self.api.handle(remote_addr, request)
-
-
- except Exception, fault:
- raise
- # This should only happen if the module is buggy
- # internal error, report as HTTP server error
- self.send_response(500)
- self.end_headers()
- logger.log_exc("componentserver.SecureXMLRpcRequestHandler.do_POST")
- else:
- # got a valid XML RPC response
- self.send_response(200)
- self.send_header("Content-type", "text/xml")
- self.send_header("Content-length", str(len(response)))
- self.end_headers()
- self.wfile.write(response)
-
- # shut down the connection
- self.wfile.flush()
- self.connection.shutdown() # Modified here!
-
-##
-# Implements an HTTPS XML-RPC server. Generally it is expected that SFA
-# functions will take a credential string, which is passed to
-# decode_authentication. Decode_authentication() will verify the validity of
-# the credential, and verify that the user is using the key that matches the
-# GID supplied in the credential.
-
-class ComponentServer(threading.Thread):
-
- ##
- # Create a new SfaServer object.
- #
- # @param ip the ip address to listen on
- # @param port the port to listen on
- # @param key_file private key filename of registry
- # @param cert_file certificate filename containing public key
- # (could be a GID file)
-
- def __init__(self, ip, port, key_file, cert_file, api=None):
- threading.Thread.__init__(self)
- self.key = Keypair(filename = key_file)
- self.cert = Certificate(filename = cert_file)
- self.server = ThreadedServer((ip, port), SecureXMLRpcRequestHandler, key_file, cert_file)
- self.trusted_cert_list = None
- self.register_functions()
-
-
- ##
- # Register functions that will be served by the XMLRPC server. This
- # function should be overrided by each descendant class.
-
- def register_functions(self):
- self.server.register_function(self.noop)
-
- ##
- # Sample no-op server function. The no-op function decodes the credential
- # that was passed to it.
-
- def noop(self, cred, anything):
- return anything
-
- ##
- # Execute the server, serving requests forever.
-
- def run(self):
- self.server.serve_forever()
-
-