Issue #19500: Add client-side SSL session resumption to the ssl module.
diff --git a/Lib/ssl.py b/Lib/ssl.py
index f3da464..df5e98e 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -99,7 +99,7 @@
 import _ssl             # if we can't import it, let the error propagate
 
 from _ssl import OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_INFO, OPENSSL_VERSION
-from _ssl import _SSLContext, MemoryBIO
+from _ssl import _SSLContext, MemoryBIO, SSLSession
 from _ssl import (
     SSLError, SSLZeroReturnError, SSLWantReadError, SSLWantWriteError,
     SSLSyscallError, SSLEOFError,
@@ -391,18 +391,18 @@
     def wrap_socket(self, sock, server_side=False,
                     do_handshake_on_connect=True,
                     suppress_ragged_eofs=True,
-                    server_hostname=None):
+                    server_hostname=None, session=None):
         return SSLSocket(sock=sock, server_side=server_side,
                          do_handshake_on_connect=do_handshake_on_connect,
                          suppress_ragged_eofs=suppress_ragged_eofs,
                          server_hostname=server_hostname,
-                         _context=self)
+                         _context=self, _session=session)
 
     def wrap_bio(self, incoming, outgoing, server_side=False,
-                 server_hostname=None):
+                 server_hostname=None, session=None):
         sslobj = self._wrap_bio(incoming, outgoing, server_side=server_side,
                                 server_hostname=server_hostname)
-        return SSLObject(sslobj)
+        return SSLObject(sslobj, session=session)
 
     def set_npn_protocols(self, npn_protocols):
         protos = bytearray()
@@ -572,10 +572,12 @@
      * The ``do_handshake_on_connect`` and ``suppress_ragged_eofs`` machinery.
     """
 
-    def __init__(self, sslobj, owner=None):
+    def __init__(self, sslobj, owner=None, session=None):
         self._sslobj = sslobj
         # Note: _sslobj takes a weak reference to owner
         self._sslobj.owner = owner or self
+        if session is not None:
+            self._sslobj.session = session
 
     @property
     def context(self):
@@ -587,6 +589,20 @@
         self._sslobj.context = ctx
 
     @property
+    def session(self):
+        """The SSLSession for client socket."""
+        return self._sslobj.session
+
+    @session.setter
+    def session(self, session):
+        self._sslobj.session = session
+
+    @property
+    def session_reused(self):
+        """Was the client session reused during handshake"""
+        return self._sslobj.session_reused
+
+    @property
     def server_side(self):
         """Whether this is a server-side socket."""
         return self._sslobj.server_side
@@ -703,7 +719,7 @@
                  family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None,
                  suppress_ragged_eofs=True, npn_protocols=None, ciphers=None,
                  server_hostname=None,
-                 _context=None):
+                 _context=None, _session=None):
 
         if _context:
             self._context = _context
@@ -735,11 +751,16 @@
         # mixed in.
         if sock.getsockopt(SOL_SOCKET, SO_TYPE) != SOCK_STREAM:
             raise NotImplementedError("only stream sockets are supported")
-        if server_side and server_hostname:
-            raise ValueError("server_hostname can only be specified "
-                             "in client mode")
+        if server_side:
+            if server_hostname:
+                raise ValueError("server_hostname can only be specified "
+                                 "in client mode")
+            if _session is not None:
+                raise ValueError("session can only be specified in "
+                                 "client mode")
         if self._context.check_hostname and not server_hostname:
             raise ValueError("check_hostname requires server_hostname")
+        self._session = _session
         self.server_side = server_side
         self.server_hostname = server_hostname
         self.do_handshake_on_connect = do_handshake_on_connect
@@ -775,7 +796,8 @@
             try:
                 sslobj = self._context._wrap_socket(self, server_side,
                                                     server_hostname)
-                self._sslobj = SSLObject(sslobj, owner=self)
+                self._sslobj = SSLObject(sslobj, owner=self,
+                                         session=self._session)
                 if do_handshake_on_connect:
                     timeout = self.gettimeout()
                     if timeout == 0.0:
@@ -796,6 +818,24 @@
         self._context = ctx
         self._sslobj.context = ctx
 
+    @property
+    def session(self):
+        """The SSLSession for client socket."""
+        if self._sslobj is not None:
+            return self._sslobj.session
+
+    @session.setter
+    def session(self, session):
+        self._session = session
+        if self._sslobj is not None:
+            self._sslobj.session = session
+
+    @property
+    def session_reused(self):
+        """Was the client session reused during handshake"""
+        if self._sslobj is not None:
+            return self._sslobj.session_reused
+
     def dup(self):
         raise NotImplemented("Can't dup() %s instances" %
                              self.__class__.__name__)
@@ -1028,7 +1068,8 @@
         if self._connected:
             raise ValueError("attempt to connect already-connected SSLSocket!")
         sslobj = self.context._wrap_socket(self, False, self.server_hostname)
-        self._sslobj = SSLObject(sslobj, owner=self)
+        self._sslobj = SSLObject(sslobj, owner=self,
+                                 session=self._session)
         try:
             if connect_ex:
                 rc = socket.connect_ex(self, addr)