view src/os/unix/ngx_recv.c @ 326:9fc4ab6673f9 NGINX_0_6_7

nginx 0.6.7 *) Change: now the paths specified in the "include", "auth_basic_user_file", "perl_modules", "ssl_certificate", "ssl_certificate_key", and "ssl_client_certificate" directives are relative to directory of nginx configuration file nginx.conf, but not to nginx prefix directory. *) Change: the --sysconfdir=PATH option in configure was canceled. *) Change: the special make target "upgrade1" was defined for online upgrade of 0.1.x versions. *) Feature: the "server_name" and "valid_referers" directives support regular expressions. *) Feature: the "server" directive in the "upstream" context supports the "backup" parameter. *) Feature: the ngx_http_perl_module supports the $r->discard_request_body. *) Feature: the "add_header Last-Modified ..." directive changes the "Last-Modified" response header line. *) Bugfix: if an response different than 200 was returned to an request with body and connection went to the keep-alive state after the request, then nginx returned 400 for the next request. *) Bugfix: a segmentation fault occurred in worker process if invalid address was set in the "auth_http" directive. *) Bugfix: now nginx uses default listen backlog value 511 on all platforms except FreeBSD. Thanks to Jiang Hong. *) Bugfix: a worker process may got caught in an endless loop, if an "server" inside "upstream" block was marked as "down"; bug appeared in 0.6.6. *) Bugfix: now Solaris sendfilev() is not used to transfer the client request body to FastCGI-server via the unix domain socket.
author Igor Sysoev <http://sysoev.ru>
date Wed, 15 Aug 2007 00:00:00 +0400
parents fae16d0c5bf4
children 583decdb82a4
line wrap: on
line source


/*
 * Copyright (C) Igor Sysoev
 */


#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>


#if (NGX_HAVE_KQUEUE)

ssize_t ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size)
{
    ssize_t       n;
    ngx_err_t     err;
    ngx_event_t  *rev;

    rev = c->read;

    if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
                       "recv: eof:%d, avail:%d, err:%d",
                       rev->pending_eof, rev->available, rev->kq_errno);

        if (rev->available == 0) {
            if (rev->pending_eof) {
                rev->ready = 0;
                rev->eof = 1;

                if (rev->kq_errno) {
                    rev->error = 1;
                    ngx_set_socket_errno(rev->kq_errno);

                    return ngx_connection_error(c, rev->kq_errno,
                               "kevent() reported about an closed connection");
                }

                return 0;

            } else {
                return NGX_AGAIN;
            }
        }
    }

    do {
        n = recv(c->fd, buf, size, 0);

        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
                       "recv: fd:%d %d of %d", c->fd, n, size);

        if (n >= 0) {
            if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
                rev->available -= n;

                /*
                 * rev->available may be negative here because some additional
                 * bytes may be received between kevent() and recv()
                 */

                if (rev->available <= 0) {
                    if (!rev->pending_eof) {
                        rev->ready = 0;
                    }

                    if (rev->available < 0) {
                        rev->available = 0;
                    }
                }

                if (n == 0) {

                    /*
                     * on FreeBSD recv() may return 0 on closed socket
                     * even if kqueue reported about available data
                     */

#if 0
                    ngx_log_error(NGX_LOG_ALERT, c->log, 0,
                                  "recv() returned 0 while kevent() reported "
                                  "%d available bytes", rev->available);
#endif

                    rev->eof = 1;
                    rev->available = 0;
                }

                return n;
            }

            if ((size_t) n < size) {
                rev->ready = 0;
            }

            if (n == 0) {
                rev->eof = 1;
            }

            return n;
        }

        err = ngx_socket_errno;

        if (err == NGX_EAGAIN || err == NGX_EINTR) {
            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
                           "recv() not ready");
            n = NGX_AGAIN;

        } else {
            n = ngx_connection_error(c, err, "recv() failed");
            break;
        }

    } while (err == NGX_EINTR);

    rev->ready = 0;

    if (n == NGX_ERROR){
        rev->error = 1;
    }

    return n;
}

#else /* ! NGX_HAVE_KQUEUE */

ssize_t ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size)
{
    ssize_t       n;
    ngx_err_t     err;
    ngx_event_t  *rev;

    rev = c->read;

    do {
        n = recv(c->fd, buf, size, 0);

        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
                       "recv: fd:%d %d of %d", c->fd, n, size);

        if (n == 0) {
            rev->ready = 0;
            rev->eof = 1;
            return n;

        } else if (n > 0) {

            if ((size_t) n < size
                && !(ngx_event_flags & NGX_USE_GREEDY_EVENT))
            {
                rev->ready = 0;
            }

            return n;
        }

        err = ngx_socket_errno;

        if (err == NGX_EAGAIN || err == NGX_EINTR) {
            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
                           "recv() not ready");
            n = NGX_AGAIN;

        } else {
            n = ngx_connection_error(c, err, "recv() failed");
            break;
        }

    } while (err == NGX_EINTR);

    rev->ready = 0;

    if (n == NGX_ERROR){
        rev->error = 1;
    }

    return n;
}

#endif /* NGX_HAVE_KQUEUE */