asyncore/asynchat do not notify connection errors on Wintel?

Abdullah Yoldas apocode at gmail.com
Thu Mar 16 08:38:21 EST 2006


Normally when you make a nonblocking connect, socket gets EINPROGRESS, later
the result of this request will appear after select returns.

I think asyncore/asynchat incorrectly interprets asychronous connects.
Reading Steven's book, I did some modifications to asyncore.dispatcher and
asynchat.async_chat as below to correctly interpret errors like:
ECONNREFUSED, ETIMEDOUT, ENETUNREACH, EHOSTUNREACH, ENETDOWN. Then I used my
custom base classes. In the code below I only show the approach for this
situation. I have other modifications for other problems (infinte recursions
etc.) but those are not shown here.

The reason is that when a socket connection makes "connect", the descriptor
becomes both readable and writable at the same time if there is a problem in
"connect". However, asyncore polling mechanism gets "readable ready" and
"writable ready" separately. Therefore, it cannot detect "connect" errors.
If you consider writability as a healthy condition (incorrectly) you would
try to write without a connection establishment, this gives some other error
but not the actual error, in handle_error().

Full discussion of nonblocking connects can be found in chapter 16 of the
book "UNIX Network Programming Volume 1, Third Edition The Sockets
Networking API, W. Richard Stevens, Bill Fenner, Andrew M. Rudoff"

Here is my approach:

# drive from asyncore.dispatcher:
class base_channel(asyncore.dispatcher):

    def handle_read_event(self):
        if self.accepting:
            if not self.connected:
                self.connected = 1
            self.handle_accept()
        elif not self.connected:
            self.handle_connect_event()
        else:
            self.handle_read()

    def handle_write_event(self):
        if not self.connected:
            self.handle_connect_event()
        else:
            self.handle_write()

    def handle_connect_event(self):
        err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
        if err:
            raise socket.error, (err, os.strerror(err))
        self.connected = 1
        self.handle_connect()

# I mix the above base_channel

class base_chatter(base_channel, asynchat.async_chat):
    def __init__ (self, conn=None):
        base_channel.__init__(self, conn)
        self.ac_in_buffer = ''
        self.ac_out_buffer = ''
        self.producer_fifo = asynchat.fifo()

    def handle_close(self):
        asynchat.async_chat.handle_close(self)

    def handle_read(self):
        asynchat.async_chat.handle_read(self)

    def handle_write(self):
        asynchat.async_chat.handle_write(self)

    def readable(self):
        return asynchat.async_chat.readable(self)

    def writable(self):
        return asynchat.async_chat.writable(self)
Abdullah Yoldas

On 3/15/06, Z. Kotzer <znewsgrp at 1zk.net> wrote:
>
> I can not get error notifications when an asynchat based client tries to
> connect to a non-responsive address.
>
> To validate the problem I changed lib/test/test_asynchat.py as follows:
>
>
> class echo_client(asynchat.async_chat):
>    def __init__(self):
>        asynchat.async_chat.__init__(self)
>        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
>        self.connect(('10.135.0.2', PORT)) # <<<<<<<< Instead of HOST - set
> an address that does not listen to this port
>        self.set_terminator("\n")
>        self.buffer = ""
>
>    # <<<<<<<<<<<<<<< And added an error handler
>    def handle_error(self):
>        print 'ERROR'
>
>
> Running it prints nothing - handle_error is not called and nothing is
> raised
> from asyncore.loop().
>
> Debugging it shows that asyncore.connect gets EWOULDBLOCK and returns
> normally (as may be expected), select in asyncore.poll returns nothing
> (including empty e) and the socket remains forever.
>
> Anybody has an experience with this behaviour?
>
> Thanks in advance!
>
>
> --
> http://mail.python.org/mailman/listinfo/python-list
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20060316/963a0b10/attachment.html>


More information about the Python-list mailing list