Fix relocation ssl/tls support

* Make a wrapper of read/write sock.fileno().

 * Makes pyOpenSSL an optional package.

 * Implement reference:
   http://twistedmatrix.com/trac/browser/trunk/twisted/internet/tcp.py

Signed-off-by: Zhigang Wang <zhigang.x.wang@oracle.com>
This commit is contained in:
Keir Fraser committed 2008-05-13 09:19:07 +01:00
1 parent 499681128c
commit 6c922a2cef
4 files changed
+243 -17

No files matched your search

+163
View File
@@ -18,12 +18,18 @@
#============================================================================
import sys
import os
import threading
import socket
import fcntl
from errno import EAGAIN, EINTR, EWOULDBLOCK
try:
from OpenSSL import SSL
except ImportError:
pass
from xen.xend.XendLogging import log
"""General classes to support server and client sockets, without
@@ -115,6 +121,163 @@ class SocketListener:
self.close()
class SSLSocketServerConnection(SocketServerConnection):
"""An SSL aware accepted connection to a server.
As pyOpenSSL SSL.Connection fileno() method just retrieve the file
descriptor number for the underlying socket, direct read/write to the file
descriptor will result no data encrypted.
recv2fd() and fd2send() are simple wrappers for functions who need direct
read/write to a file descriptor rather than a socket like object.
To use recv2fd(), you can create a pipe and start a thread to transfer all
received data to one end of the pipe, then read from the other end:
p2cread, p2cwrite = os.pipe()
threading.Thread(target=connection.recv2fd, args=(sock, p2cwrite)).start()
os.read(p2cread, 1024)
To use fd2send():
p2cread, p2cwrite = os.pipe()
threading.Thread(target=connection.fd2send, args=(sock, p2cread)).start()
os.write(p2cwrite, "data")
"""
def __init__(self, sock, protocol_class):
SocketServerConnection.__init__(self, sock, protocol_class)
def main(self):
try:
while True:
try:
data = self.sock.recv(BUFFER_SIZE)
if data == "":
break
if self.protocol.dataReceived(data):
break
except socket.error, ex:
if ex.args[0] not in (EWOULDBLOCK, EAGAIN, EINTR):
break
except (SSL.WantReadError, SSL.WantWriteError, \
SSL.WantX509LookupError):
# The operation did not complete; the same I/O method
# should be called again.
continue
except SSL.ZeroReturnError:
# The SSL Connection has been closed.
break
except SSL.SysCallError, (retval, desc):
if ((retval == -1 and desc == "Unexpected EOF")
or retval > 0):
# The SSL Connection is lost.
break
log.debug("SSL SysCallError:%d:%s" % (retval, desc))
break
except SSL.Error, e:
# other SSL errors
log.debug("SSL Error:%s" % e)
break
finally:
try:
self.sock.close()
except:
pass
def recv2fd(sock, fd):
try:
while True:
try:
data = sock.recv(BUFFER_SIZE)
if data == "":
break
count = 0
while count < len(data):
try:
nbytes = os.write(fd, data[count:])
count += nbytes
except os.error, ex:
if ex.args[0] not in (EWOULDBLOCK, EAGAIN, EINTR):
raise
except socket.error, ex:
if ex.args[0] not in (EWOULDBLOCK, EAGAIN, EINTR):
break
except (SSL.WantReadError, SSL.WantWriteError, \
SSL.WantX509LookupError):
# The operation did not complete; the same I/O method
# should be called again.
continue
except SSL.ZeroReturnError:
# The SSL Connection has been closed.
break
except SSL.SysCallError, (retval, desc):
if ((retval == -1 and desc == "Unexpected EOF")
or retval > 0):
# The SSL Connection is lost.
break
log.debug("SSL SysCallError:%d:%s" % (retval, desc))
break
except SSL.Error, e:
# other SSL errors
log.debug("SSL Error:%s" % e)
break
finally:
try:
sock.close()
os.close(fd)
except:
pass
recv2fd = staticmethod(recv2fd)
def fd2send(sock, fd):
try:
while True:
try:
data = os.read(fd, BUFFER_SIZE)
if data == "":
break
count = 0
while count < len(data):
try:
nbytes = sock.send(data[count:])
count += nbytes
except socket.error, ex:
if ex.args[0] not in (EWOULDBLOCK, EAGAIN, EINTR):
raise
except (SSL.WantReadError, SSL.WantWriteError, \
SSL.WantX509LookupError):
# The operation did not complete; the same I/O method
# should be called again.
continue
except SSL.ZeroReturnError:
# The SSL Connection has been closed.
raise
except SSL.SysCallError, (retval, desc):
if not (retval == -1 and data == ""):
# errors when writing empty strings are expected
# and can be ignored
log.debug("SSL SysCallError:%d:%s" % (retval, desc))
raise
except SSL.Error, e:
# other SSL errors
log.debug("SSL Error:%s" % e)
raise
except os.error, ex:
if ex.args[0] not in (EWOULDBLOCK, EAGAIN, EINTR):
break
finally:
try:
sock.close()
os.close(fd)
except:
pass
fd2send = staticmethod(fd2send)
def hostAllowed(addrport, hosts_allowed):
if hosts_allowed is None:
return True
+12
View File
@@ -88,6 +88,7 @@ class SSLTCPListener(TCPListener):
ctx.use_certificate_file(self.ssl_cert_file)
sock = SSL.Connection(ctx,
socket.socket(socket.AF_INET, socket.SOCK_STREAM))
sock.set_accept_state()
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# SO_REUSEADDR does not always ensure that we do not get an address
@@ -104,3 +105,14 @@ class SSLTCPListener(TCPListener):
else:
raise
def acceptConnection(self, sock, addrport):
addr = addrport[0]
if connection.hostAllowed(addrport, self.hosts_allow):
connection.SSLSocketServerConnection(sock, self.protocol_class)
else:
try:
sock.close()
except:
pass
+47 -16
View File
@@ -1293,25 +1293,56 @@ class XendDomain:
if port == 0:
port = xoptions.get_xend_relocation_port()
try:
tls = xoptions.get_xend_relocation_tls()
if tls:
from OpenSSL import SSL
tls = xoptions.get_xend_relocation_tls()
if tls:
from OpenSSL import SSL
from xen.web import connection
try:
ctx = SSL.Context(SSL.SSLv23_METHOD)
sock = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
sock = SSL.Connection(ctx,
socket.socket(socket.AF_INET, socket.SOCK_STREAM))
sock.set_connect_state()
else:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((dst, port))
except socket.error, err:
raise XendError("can't connect: %s" % err[1])
sock.connect((dst, port))
sock.send("sslreceive\n")
sock.recv(80)
except SSL.Error, err:
raise XendError("SSL error: %s" % err)
except socket.error, err:
raise XendError("can't connect: %s" % err)
sock.send("receive\n")
sock.recv(80)
try:
XendCheckpoint.save(sock.fileno(), dominfo, True, live, dst, node=node)
finally:
sock.close()
p2cread, p2cwrite = os.pipe()
threading.Thread(target=connection.SSLSocketServerConnection.fd2send,
args=(sock, p2cread)).start()
try:
XendCheckpoint.save(p2cwrite, dominfo, True, live, dst,
node=node)
finally:
sock.shutdown()
sock.close()
os.close(p2cread)
os.close(p2cwrite)
else:
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# When connecting to our ssl enabled relocation server using a
# plain socket, send will success but recv will block. Add a
# 30 seconds timeout to raise a socket.timeout exception to
# inform the client.
sock.settimeout(30.0)
sock.connect((dst, port))
sock.send("receive\n")
sock.recv(80)
sock.settimeout(None)
except socket.error, err:
raise XendError("can't connect: %s" % err)
try:
XendCheckpoint.save(sock.fileno(), dominfo, True, live,
dst, node=node)
finally:
sock.close()
def domain_save(self, domid, dst, checkpoint=False):
"""Start saving a domain to file.
+21 -1
View File
@@ -17,10 +17,12 @@
#============================================================================
import re
import os
import sys
import StringIO
import threading
from xen.web import protocol, tcp, unix
from xen.web import protocol, tcp, unix, connection
from xen.xend import sxp
from xen.xend import XendDomain
@@ -116,6 +118,24 @@ class RelocationProtocol(protocol.Protocol):
log.error(name + ": no transport")
raise XendError(name + ": no transport")
def op_sslreceive(self, name, _):
if self.transport:
self.send_reply(["ready", name])
p2cread, p2cwrite = os.pipe()
threading.Thread(target=connection.SSLSocketServerConnection.recv2fd,
args=(self.transport.sock, p2cwrite)).start()
try:
XendDomain.instance().domain_restore_fd(p2cread,
relocating=True)
except:
os.close(p2cread)
os.close(p2cwrite)
self.send_error()
self.close()
else:
log.error(name + ": no transport")
raise XendError(name + ": no transport")
def listenRelocation():
xoptions = XendOptions.instance()
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.