Implement Connection.recv_into.
diff --git a/OpenSSL/SSL.py b/OpenSSL/SSL.py
index 7b1cbc1..b694578 100644
--- a/OpenSSL/SSL.py
+++ b/OpenSSL/SSL.py
@@ -1027,6 +1027,45 @@
     read = recv
 
 
+    def recv_into(self, buffer, nbytes=None, flags=None):
+        """
+        Receive data on the connection and store the data into a buffer rather
+        than creating a new string.
+
+        :param buffer: The buffer to copy into.
+        :param nbytes: (optional) The maximum number of bytes to read into the
+            buffer. If not present, defaults to the size of the buffer. If
+            larger than the size of the buffer, is reduced to the size of the
+            buffer.
+        :param flags: (optional) Included for compatibility with the socket
+            API, the value is ignored.
+        :return: The number of bytes read into the buffer.
+        """
+        if nbytes is None:
+            nbytes = len(buffer)
+        else:
+            nbytes = min(nbytes, len(buffer))
+
+        # We need to create a temporary buffer. This is annoying, it would be
+        # better if we could pass memoryviews straight into the SSL_read call,
+        # but right now we can't. Revisit this if CFFI gets that ability.
+        buf = _ffi.new("char[]", nbytes)
+        result = _lib.SSL_read(self._ssl, buf, nbytes)
+        self._raise_ssl_error(self._ssl, result)
+
+        # This strange line is all to avoid a memory copy. The buffer protocol
+        # should allow us to assign a CFFI buffer to the LHS of this line, but
+        # on CPython 3.3+ that segfaults. As a workaround, we can temporarily
+        # wrap it in a memoryview, except on Python 2.6 which doesn't have a
+        # memoryview type.
+        try:
+            buffer[:result] = memoryview(_ffi.buffer(buf, result))
+        except NameError:
+            buffer[:result] = _ffi.buffer(buf, result)
+
+        return result
+
+
     def _handle_bio_errors(self, bio, result):
         if _lib.BIO_should_retry(bio):
             if _lib.BIO_should_read(bio):
diff --git a/OpenSSL/test/test_ssl.py b/OpenSSL/test/test_ssl.py
index 6409b8e..daf1924 100644
--- a/OpenSSL/test/test_ssl.py
+++ b/OpenSSL/test/test_ssl.py
@@ -2217,6 +2217,98 @@
 
 
 
+class ConnectionRecvIntoTests(TestCase, _LoopbackMixin):
+    """
+    Tests for :py:obj:`Connection.recv_into`
+    """
+    def test_recv_into_no_length(self):
+        """
+        Test that :py:obj:`Connection.recv_into` can be safely passed an object
+        using the buffer protocol.
+        """
+        server, client = self._loopback()
+        server.send(b('xy'))
+        buffer = bytearray(5)
+
+        self.assertEquals(client.recv_into(buffer), 2)
+        self.assertEquals(buffer, bytearray(b('xy\x00\x00\x00')))
+
+
+    def test_recv_into_respects_length(self):
+        """
+        Test that :py:obj:`Connection.recv_into` respects the nbytes
+        parameter and doesn't copy more than that number of bytes in.
+        """
+        server, client = self._loopback()
+        server.send(b('abcdefghij'))
+        buffer = bytearray(10)
+
+        self.assertEquals(client.recv_into(buffer, 5), 5)
+        self.assertEquals(buffer, bytearray(b('abcde\x00\x00\x00\x00\x00')))
+
+
+    def test_recv_into_doesnt_overfill(self):
+        """
+        Test that :py:obj:`Connection.recv_into` doesn't overfill an object
+        implementing the buffer protocol.
+        """
+        server, client = self._loopback()
+        server.send(b('abcdefghij'))
+        buffer = bytearray(5)
+
+        self.assertEquals(client.recv_into(buffer), 5)
+        self.assertEquals(buffer, bytearray(b('abcde')))
+
+
+    try:
+        memoryview
+    except NameError:
+        "cannot test recv_into memoryview without memoryview"
+    else:
+        def test_recv_into_memoryview_no_length(self):
+            """
+            Test that :py:obj:`Connection.recv_into` can be safely passed a
+            memoryview.
+            """
+            server, client = self._loopback()
+            server.send(b('xy'))
+            buffer = bytearray(5)
+            mv = memoryview(buffer)
+
+            self.assertEquals(client.recv_into(mv), 2)
+            self.assertEquals(buffer, bytearray(b('xy\x00\x00\x00')))
+
+
+        def test_recv_into_memoryview_respects_length(self):
+            """
+            Test that :py:obj:`Connection.recv_into` respects the nbytes
+            parameter and doesn't copy more than that number of bytes in.
+            """
+            server, client = self._loopback()
+            server.send(b('abcdefghij'))
+            buffer = bytearray(10)
+            mv = memoryview(buffer)
+
+            self.assertEquals(client.recv_into(mv, 5), 5)
+            self.assertEquals(buffer,
+                              bytearray(b('abcde\x00\x00\x00\x00\x00')))
+
+
+        def test_recv_into_memoryview_doesnt_overfill(self):
+            """
+            Test that :py:obj:`Connection.recv_into` doesn't overfill a
+            memoryview.
+            """
+            server, client = self._loopback()
+            server.send(b('abcdefghij'))
+            buffer = bytearray(5)
+            mv = memoryview(buffer)
+
+            self.assertEquals(client.recv_into(mv), 5)
+            self.assertEquals(buffer, bytearray(b('abcde')))
+
+
+
 class ConnectionSendallTests(TestCase, _LoopbackMixin):
     """
     Tests for :py:obj:`Connection.sendall`.