SSL EOF

Ng Pheng Siong ngps at madcap.dyndns.org
Thu Feb 1 12:05:00 EST 2001


According to Clarence Gardner  <clarence at netlojix.com>:
> Here is the relevant code.  I don't know what error==6 signifies, but even
> if the other side closed improperly, I don't think that's so significant as to
> warrant making these sockets behave differently from non-ssl ones.
> 
>     count = SSL_read(self->ssl, PyString_AsString(buf), len);
>     res = SSL_get_error(self->ssl, count);
> 
>     switch (res) {
>     case 0:         /* Good return value! */
>         break;
>     case 6:
>         PyErr_SetString(SSLErrorObject, "EOF");
>         Py_DECREF(buf);
>         return NULL;
>         break;
>     case 5:
>     default:
>         return PyErr_SetFromErrno(SSLErrorObject);
>         break;
> 

For comparison, here's what M2Crypto's ssl_read() looks like:

PyObject *ssl_read(SSL *ssl, int num) {
    PyObject *obj;
    void *buf;
    int r, err;

    if (!(buf = PyMem_Malloc(num))) {
        PyErr_SetString(PyExc_MemoryError, "ssl_read");
        return NULL;
    }
    Py_BEGIN_ALLOW_THREADS
    r = SSL_read(ssl, buf, num);
    Py_END_ALLOW_THREADS
    switch (SSL_get_error(ssl, r)) {
        case SSL_ERROR_NONE:
        case SSL_ERROR_ZERO_RETURN:
            buf = PyMem_Realloc(buf, r);
            obj = PyString_FromStringAndSize(buf, r);
            break;
        case SSL_ERROR_WANT_WRITE:
        case SSL_ERROR_WANT_READ:
        case SSL_ERROR_WANT_X509_LOOKUP:
            Py_INCREF(Py_None);
            obj = Py_None;
            break;
        case SSL_ERROR_SSL:
            PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error()));
            obj = NULL;
            break;
        case SSL_ERROR_SYSCALL:
            err = ERR_get_error();
            if (err)
                PyErr_SetString(_ssl_err, ERR_reason_error_string(err));
            else if (r == 0)
                PyErr_SetString(_ssl_err, "unexpected eof");
            else if (r == -1)
                PyErr_SetFromErrno(_ssl_err);
            obj = NULL;
            break;
    }
    PyMem_Free(buf);
    return obj;
}


And Python code using that, from M2Crypto's https extension to Medusa:

    def recv(self, buffer_size):
        try:
            result = self.socket._read_nbio(buffer_size)
            if result is None:
                return ''
            elif result == '':
                self.socket.set_shutdown(SSL.SSL_SENT_SHUTDOWN|SSL.SSL_RECEIVED_SHUTDOWN)
                return ''
            else:
                self.server.bytes_in.increment(len(result))
                return result
        except SSL.SSLError, why:
            self.socket.set_shutdown(SSL.SSL_SENT_SHUTDOWN|SSL.SSL_RECEIVED_SHUTDOWN)
            self.close()
            self.log_info('recv: closing channel %s %s' % (repr(self), why))
            return ''


So, in M2Crypto, ssl_read() does return a '' on eof; if the other side
failed to close properly, an SSL.SSLError exception is raised with the
error "unexpected eof".

M2Crypto works with both Python 1.5.2 and Python 2.0. Get it here:

    http://www.post1.com/home/ngps/m2

Cheers.

-- 
Ng Pheng Siong <ngps at post1.com> * http://www.post1.com/home/ngps




More information about the Python-list mailing list