Issue2374

classification
Title: setsockopt call from pika fails with "Protocol not available"error
Type: Severity: urgent
Components: Versions: Jython 2.7
Milestone: Jython 2.7.1
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: zyasoft Nosy List: mbakht, sophacles, zyasoft
Priority: Keywords:

Created on 2015-07-01.23:56:28 by mbakht, last changed 2015-11-23.21:10:18 by zyasoft.

Messages
msg10136 (view) Author: Mehedi (mbakht) Date: 2015-07-02.00:00:40
When a call is made from jython (2.7.0) code for connecting to RabbitMQ through pika.BlockingConnection, it results in the following error:

    _socket.error: [Errno 92] Protocol not available


The call to pika.BlockingConnection ends up calling the following block of code in pika
(https://github.com/pika/pika/blob/master/pika/adapters/base_connection.py#L195)


def _create_and_connect_to_socket(self, sock_addr_tuple):
        """Create socket and connect to it, using SSL if enabled.
        :returns: error string on failure; None on success
        """
        self.socket = socket.socket(sock_addr_tuple[0], socket.SOCK_STREAM, 0)


The last value passed in socket.socket(..) denotes the protocol number which is 0 in this case.

This code calls the socket method in jython's _socket.py (https://github.com/jythontools/jython/blob/master/Lib/_socket.py#L1456):


def socket(family=None, type=None, proto=None):
    return _socketobject(family, type, proto)


Since the python code made the call with proto value set to 0, that is the value that will be passed here to _socketobject.


Now, here is the code in _socketobject (https://github.com/jythontools/jython/blob/master/Lib/_socket.py#L1308):


class _socketobject(object):

    __doc__ = _realsocket.__doc__


    def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, _sock=None):
        if _sock is None:
            _sock = _realsocket(family, type, proto)


proto still has the value 0 as it gets passed down to realsocket.


class _realsocket(object):

    def __init__(self, family=None, type=None, proto=None):
        # FIXME verify args are correct
        self.family = family
        self.type = type
        if proto is None:
            if type == SOCK_STREAM:
                proto = IPPROTO_TCP
            elif type == SOCK_DGRAM:
                proto = IPPROTO_UDP
        self.proto = proto



Since proto is not None, it does not get assigned the default value of TCP. This zero value eventually causes the "Protocol not available" error.
msg10144 (view) Author: Jim Baker (zyasoft) Date: 2015-07-06.20:59:28
Same problem as #2273
msg10194 (view) Author: Erich Heine (sophacles) Date: 2015-09-01.19:35:19
This bug is affecting me as well, so I did some more digging - It turns out there are a couple of problems here... (which maybe are getting conflated somehow?)

In the constructor of socket, CPython doesn't allow None for proto. It requires an integer. 

In setsockopt after creating a socket with proto = 0. The pika module mentioned sets TCP_NODELAY after creating a socket with proto = 0. In CPython this works, but in jython it does not. 

Here is the output of a Jython session (note the bare value 6 is the value on my system for socket.SOL_TCP which is not defined in Jython a third incompatibility)

>>> import socket
>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, None)
>>> s.setsockopt(6, socket.TCP_NODELAY, 1)
>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
>>> s.setsockopt(6, socket.TCP_NODELAY, 1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/Cellar/jython/2.7.0/libexec/Lib/_socket.py", line 1367, in meth
    return getattr(self._sock,name)(*args)
  File "/usr/local/Cellar/jython/2.7.0/libexec/Lib/_socket.py", line 357, in handle_exception
    return method_or_function(*args, **kwargs)
  File "/usr/local/Cellar/jython/2.7.0/libexec/Lib/_socket.py", line 357, in handle_exception
    return method_or_function(*args, **kwargs)
  File "/usr/local/Cellar/jython/2.7.0/libexec/Lib/_socket.py", line 1204, in setsockopt
    raise error(errno.ENOPROTOOPT, "Protocol not available")
_socket.error: [Errno 42] Protocol not available

In CPython this is the output:

>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/Cellar/python/2.7.7_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 187, in __init__
    _sock = _realsocket(family, type, proto)
TypeError: an integer is required
>>> 
>>> 
>>> s = socket.socket(socekt.AF_INET, socket.SOCK_STREAM, 0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'socekt' is not defined
>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
>>> s.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)


Note that in both systems, creating the socket without passing a value to the 3rd argument of the socket constructor, setsockopt works just fine. The mismatch appears to be on explicitly setting the 3rd argument to the default value.
msg10195 (view) Author: Jim Baker (zyasoft) Date: 2015-09-01.20:37:57
Erich, thanks for your detailed analysis. This is very helpful! I'm still planning on getting this work completed in 2.7.1. Note that beta 1 is scheduled for Sept 10, however we should have enough time by Oct 8 to see this in beta 2.
msg10224 (view) Author: Jim Baker (zyasoft) Date: 2015-09-04.04:44:21
Fixed as of https://hg.python.org/jython/rev/b3b82ef080a9
msg10500 (view) Author: Jim Baker (zyasoft) Date: 2015-11-23.21:10:18
One thing we missed is the lack of socket.SOL_TCP (see msg10194). Opened a new bug for this, #2436
History
Date User Action Args
2015-11-23 21:10:18zyasoftsetmessages: + msg10500
2015-09-17 20:31:29zyasoftsetstatus: pending -> closed
2015-09-04 04:44:21zyasoftsetstatus: open -> pending
resolution: fixed
messages: + msg10224
2015-09-01 20:37:58zyasoftsetmessages: + msg10195
2015-09-01 19:35:20sophaclessetnosy: + sophacles
messages: + msg10194
2015-07-28 15:07:03zyasoftsetassignee: zyasoft
2015-07-06 20:59:28zyasoftsetnosy: + zyasoft
messages: + msg10144
milestone: Jython 2.7.1
2015-07-02 00:00:40mbakhtsetmessages: + msg10136
severity: normal -> urgent
2015-07-01 23:56:28mbakhtcreate