Subject: Re: [libssh2] libssh2_channel_read_stderr always in blocking mode ?

Re: [libssh2] libssh2_channel_read_stderr always in blocking mode ?

From: Thomas Harding <thomas.harding_at_laposte.net>
Date: Wed, 1 Aug 2007 17:56:53 +0200

>>On Tue, 31 Jul 2007, Thomas Harding wrote:
>Daniel Stenberg <daniel_at_haxx.se>
>
>>My problem is that while using libssh2_channel_read_stderr, it seems to
>>wait infinitely for data when no data is available, whatever channel is or
>>is not in blocking mode.
>
>Can you please provide a complete small source snippet that reproduces the
>problem?

Well, maybe the better will be to me to write such this, but it is not
done... hope following code will be enough explicit.

Complete source code:
http://tom.harding.free.fr/vrac/python-ssh2.tgz
edit and run files in test dir

###################
# read_stderr function
###################
static PyObject *
SSH2_Channel_readstderr(SSH2_ChannelObj *self, PyObject *args)
{
    int bufsiz, ret=0;
    //~ unsigned char *buf[1024];
    PyObject *buf;
    
    if (!PyArg_ParseTuple(args, "i:read", &bufsiz))
        return NULL;
    
    buf = PyString_FromStringAndSize(NULL, bufsiz);
        if (buf == NULL)
            return NULL;
    
    if (libssh2_channel_eof(self->channel)!=1)
    {
        
        MY_BEGIN_ALLOW_THREADS(self->tstate);
        ret = libssh2_channel_read_stderr(self->channel, PyString_AsString(buf), bufsiz);
        MY_END_ALLOW_THREADS(self->tstate);
        
        if (ret > 0)
        {
            if (ret != bufsiz && _PyString_Resize(&buf, ret) < 0)
            {
                return NULL;
            }
            return buf;
        }
    }
    
    Py_DECREF(buf);
    Py_INCREF(Py_None);
    return Py_None;
}

######################
#
# Popen function
#####################
static PyObject *
SSH2_Session_popen(SSH2_SessionObj *self, PyObject *args)
{
    LIBSSH2_CHANNEL *channel;
    char *command;

    if (!PyArg_ParseTuple(args, "s:popen", &command))
        return NULL;

    channel = libssh2_channel_open_session(self->session);
    if (channel == NULL) {
        PyErr_SetString(PySSH2_Error, "SSH error.");
        return NULL;
    }
    if (libssh2_channel_exec(channel, command)) {
        PyErr_SetString(PySSH2_Error, "Unable to request command execution on remote host");
        libssh2_channel_free(channel);
    }

     return (PyObject *)(SSH2_Channel_New(channel, 1));
}
#################
 Python code
#################
        def testPopenBlocking(self):
                ssh = SSH2.Session()
                ssh.setBanner(SSH2.DEFAULT_BANNER)
                ssh.startup(self.getConnexion())
                ssh.setPassword(LOGIN, PWD)
                channel = ssh.popen(command)
                print channel
                if channel:
                        channel.setBlocking(True)
                        while 1:
                                if channel.eof():
                                        print "EOF"
                                         break
                                data = channel.read(BUFFER)
                                if data:
                                        sys.stdout.write(data)
                                errors = None
                                errors = channel.readstderr(BUFFER)
                                if errors:
                                        sys.stderr.write(errors)
                                if channel.eof():
                                        print "EOF"
                                         break
                ssh.close()
        
        def testPopenNonBlocking(self):
                print "#########################"
                print "#"
                print "# test Popen Non Blocking"
                print "#"
                print "#########################"
                time.sleep(2)
                ssh = SSH2.Session()
                ssh.setBanner(SSH2.DEFAULT_BANNER)
                ssh.startup(self.getConnexion())
                ssh.setPassword(LOGIN, PWD)
                channel = ssh.popen(command)
                print channel
                l = 0
                el = 0
                outputfile = open("testPopenNonBlocking","wb")
                errorsfile = open("testPopenNonBlocking_err","wb")
                if channel:
                        channel.setBlocking(False)
                        while 1:
                                if channel.eof():
                                        print "EOF"
                                         break
                                if not channel.poll(100,[SSH2.LIBSSH2_POLLFD_POLLIN,SSH2.LIBSSH2_POLLFD_POLLPRI]):
                                        print "no data"
                                        raise Exception('File incomplete')
                                data = channel.read(BUFFER) # BUF represente la quantite maximum de donnees, mais on recuperer moins
                                if data:
                                        sys.stdout.write(data)
                                        outputfile.write(data)
                                        l += len(data)
                                errors = None
                                if channel.poll(10,[SSH2.LIBSSH2_POLLFD_POLLEXT]):
                                        errors = channel.readstderr(BUFFER)
                                        print "\nerror\n"
                                if errors is not None:
                                        sys.stderr.write("Error" + errors)
                                        el += len(errors)
                                        errorsfile.write(errors)
                ssh.close()
                print "data lenght: %s\nerror lenght: %s" %(l,el)
                time.sleep(2)

>>I (half) solved the problem in non-blocking mode by polling for POLLERR (it
>>seems to differs from the unix poll, as POLLERR is normally not significant
>>in pollfd struct) "half", because since an error occurs, calling
>>libssh2_poll on POLLERR success everytime. In that case, reading for stderr
>>sipmly returns nothing (it doesn't block).
>
>Actually, I find very little use for libssh2_poll() at all... When is that
>ever useful? Since connections etc already are done outside the library the
>application already knows the sockets etc and could just as well just use
>regular poll(). Or what am I missing?

Maybe a I'm wrong on (libssh2_)poll use: I would to check if data is
available before to try to read it, because in the case where is nothing
to read, program waits infinitely for data (and as I said, channel EOF
never matches in blocking mode after a channel_exec).

I'm not experienced in network programming: basically, I just coded web
php programs and a few libraries (as one php library which copes with
IPP)

-- 
Thomas Harding
-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/
_______________________________________________
libssh2-devel mailing list
libssh2-devel_at_lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libssh2-devel
Received on 2007-08-01