classification
Title: Unconnected SSLSocket.{send,recv} raises TypeError: 'member_descriptor' object is not callable
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 2.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: pitrou Nosy List: giampaolo.rodola, pitrou, spiv
Priority: normal Keywords: patch

Created on 2010-09-01 02:32 by spiv, last changed 2010-09-14 14:37 by pitrou. This issue is now closed.

Files
File name Uploaded Description Edit
issue9729.patch spiv, 2010-09-14 06:28 Fix for Python 2.7
issue9729-2.patch pitrou, 2010-09-14 13:06
issue9729-3.patch pitrou, 2010-09-14 13:36
Messages (8)
msg115286 - (view) Author: Andrew Bennetts (spiv) Date: 2010-09-01 02:32
ython 2.6.6 (r266:84292, Aug 24 2010, 21:47:18) 
[GCC 4.4.5 20100816 (prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket, ssl
>>> s = socket.socket()
>>> wrapped = ssl.wrap_socket(s)
>>> wrapped.recv(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.6/ssl.py", line 217, in recv
    return socket.recv(self, buflen, flags)
TypeError: 'member_descriptor' object is not callable


What I expected was a more helpful error, like the unwrapped socket gives:

>> s.recv(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
socket.error: [Errno 107] Transport endpoint is not connected


The full list of affected methods are all the _delegate_methods from socket.py:

_delegate_methods = ("recv", "recvfrom", "recv_into", "recvfrom_into",
                     "send", "sendto")

The cause is that the SSLSocket subclass is trying to upcall to the _socketobject base class, but the base does not have methods for those, just __slots__ for the instance to fill in with bound methods.
msg115292 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2010-09-01 12:38
Note that 3.x will give you the expected error message:
>>> s = socket.socket()
>>> wrapped = ssl.wrap_socket(s)
>>> wrapped.recv(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/antoine/py3k/__svn__/Lib/ssl.py", line 292, in recv
    return socket.recv(self, buflen, flags)
socket.error: [Errno 107] Transport endpoint is not connected

Do you have any idea how to solve it for 2.7? Do you want to provide a patch?
msg116370 - (view) Author: Andrew Bennetts (spiv) Date: 2010-09-14 06:28
Here's a conservative fix for Python 2.7.  It replaces the attempts to call baseclass.method with direct calls to the decorated object (i.e. replace socket.meth(self, ...) with self._sock.meth(...)).

It also corrects a bunch of incorrect arguments being passed to _sock... it's pretty clear this code was not tested.  I've added a test that exercises each SSLSocket method that corresponds to a socket._delegate_method.

A nicer solution is to simply make socket.socket actually be a simple subclass of _socket.socket rather than the weird decorator it is now.  This has already happened on the py3k branch, which is why it doesn't have this bug.
msg116381 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2010-09-14 10:28
Nice, thank you. I will look at the patch and commit it if everything's fine.

> A nicer solution is to simply make socket.socket actually be a simple
> subclass of _socket.socket rather than the weird decorator it is now. 
> This has already happened on the py3k branch, which is why it doesn't
> have this bug.

Yes, but such a rearchitecting to the socket module is out of question for 2.x, which is in bugfix mode.
msg116394 - (view) Author: Andrew Bennetts (spiv) Date: 2010-09-14 12:43
> Yes, but such a rearchitecting to the socket module is out of question 
> for 2.x, which is in bugfix mode.

Yes of course, which is why I made the conservative fix instead :)
msg116396 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2010-09-14 13:06
The recvfrom() signature is wrong (it doesn't take an address argument). Here is an updated patch.
msg116398 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2010-09-14 13:36
sendto() has a similar problem. socket.sendto() takes (data, flags=0, addr), but SSLSocket.sendto() incorrectly forwards the arguments. Updated patch attached.
msg116402 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2010-09-14 14:37
Patch committed in r84806.
History
Date User Action Args
2010-09-14 14:37:48pitrousetstatus: open -> closed
resolution: fixed
messages: + msg116402

stage: commit review -> resolved
2010-09-14 13:36:14pitrousetfiles: + issue9729-3.patch

messages: + msg116398
2010-09-14 13:06:51pitrousetfiles: + issue9729-2.patch

messages: + msg116396
2010-09-14 12:43:17spivsetmessages: + msg116394
2010-09-14 10:28:46pitrousetassignee: pitrou
messages: + msg116381
stage: needs patch -> commit review
2010-09-14 06:28:09spivsetfiles: + issue9729.patch
keywords: + patch
messages: + msg116370
2010-09-01 20:28:07giampaolo.rodolasetnosy: + giampaolo.rodola
2010-09-01 12:38:45pitrousetversions: - Python 2.6
nosy: + pitrou

messages: + msg115292

components: + Library (Lib)
stage: needs patch
2010-09-01 02:32:43spivsettype: behavior
2010-09-01 02:32:22spivcreate