utils.log: Split formatter building into separate function
[ganeti-local] / lib / http / __init__.py
index 965a297..9049829 100644 (file)
@@ -1,7 +1,7 @@
 #
 #
 
-# Copyright (C) 2007, 2008 Google Inc.
+# Copyright (C) 2007, 2008, 2010 Google Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -323,44 +323,6 @@ class HttpVersionNotSupported(HttpException):
   code = 505
 
 
-def WaitForSocketCondition(sock, event, timeout):
-  """Waits for a condition to occur on the socket.
-
-  @type sock: socket
-  @param sock: Wait for events on this socket
-  @type event: int
-  @param event: ORed condition (see select module)
-  @type timeout: float or None
-  @param timeout: Timeout in seconds
-  @rtype: int or None
-  @return: None for timeout, otherwise occured conditions
-
-  """
-  check = (event | select.POLLPRI |
-           select.POLLNVAL | select.POLLHUP | select.POLLERR)
-
-  if timeout is not None:
-    # Poller object expects milliseconds
-    timeout *= 1000
-
-  poller = select.poll()
-  poller.register(sock, event)
-  try:
-    while True:
-      # TODO: If the main thread receives a signal and we have no timeout, we
-      # could wait forever. This should check a global "quit" flag or
-      # something every so often.
-      io_events = poller.poll(timeout)
-      if not io_events:
-        # Timeout
-        return None
-      for (_, evcond) in io_events:
-        if evcond & check:
-          return evcond
-  finally:
-    poller.unregister(sock)
-
-
 def SocketOperation(sock, op, arg1, timeout):
   """Wrapper around socket functions.
 
@@ -411,7 +373,7 @@ def SocketOperation(sock, op, arg1, timeout):
       else:
         wait_for_event = event_poll
 
-      event = WaitForSocketCondition(sock, wait_for_event, timeout)
+      event = utils.WaitForFdCondition(sock, wait_for_event, timeout)
       if event is None:
         raise HttpSocketTimeout()
 
@@ -588,6 +550,7 @@ class HttpSslParams(object):
     """
     self.ssl_key_pem = utils.ReadFile(ssl_key_path)
     self.ssl_cert_pem = utils.ReadFile(ssl_cert_path)
+    self.ssl_cert_path = ssl_cert_path
 
   def GetKey(self):
     return OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM,
@@ -608,7 +571,7 @@ class HttpBase(object):
     self._ssl_key = None
     self._ssl_cert = None
 
-  def _CreateSocket(self, ssl_params, ssl_verify_peer):
+  def _CreateSocket(self, ssl_params, ssl_verify_peer, family):
     """Creates a TCP socket and initializes SSL if needed.
 
     @type ssl_params: HttpSslParams
@@ -616,11 +579,14 @@ class HttpBase(object):
     @type ssl_verify_peer: bool
     @param ssl_verify_peer: Whether to require client certificate
         and compare it with our certificate
+    @type family: int
+    @param family: socket.AF_INET | socket.AF_INET6
 
     """
-    self._ssl_params = ssl_params
+    assert family in (socket.AF_INET, socket.AF_INET6)
 
-    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    self._ssl_params = ssl_params
+    sock = socket.socket(family, socket.SOCK_STREAM)
 
     # Should we enable SSL?
     self.using_ssl = ssl_params is not None
@@ -634,6 +600,10 @@ class HttpBase(object):
     ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
     ctx.set_options(OpenSSL.SSL.OP_NO_SSLv2)
 
+    ciphers = self.GetSslCiphers()
+    logging.debug("Setting SSL cipher string %s", ciphers)
+    ctx.set_cipher_list(ciphers)
+
     ctx.use_privatekey(self._ssl_key)
     ctx.use_certificate(self._ssl_cert)
     ctx.check_privatekey()
@@ -643,8 +613,23 @@ class HttpBase(object):
                      OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
                      self._SSLVerifyCallback)
 
+      # Also add our certificate as a trusted CA to be sent to the client.
+      # This is required at least for GnuTLS clients to work.
+      try:
+        # This will fail for PyOpenssl versions before 0.10
+        ctx.add_client_ca(self._ssl_cert)
+      except AttributeError:
+        # Fall back to letting OpenSSL read the certificate file directly.
+        ctx.load_client_ca(ssl_params.ssl_cert_path)
+
     return OpenSSL.SSL.Connection(ctx, sock)
 
+  def GetSslCiphers(self): # pylint: disable-msg=R0201
+    """Returns the ciphers string for SSL.
+
+    """
+    return constants.OPENSSL_CIPHERS
+
   def _SSLVerifyCallback(self, conn, cert, errnum, errdepth, ok):
     """Verify the certificate provided by the peer