1
2/*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8#include <ngx_config.h>
9#include <ngx_core.h>
10#include <ngx_event.h>
11
12
13ssize_t
14ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size)
15{
16    ssize_t       n;
17    ngx_err_t     err;
18    ngx_event_t  *rev;
19
20    rev = c->read;
21
22#if (NGX_HAVE_KQUEUE)
23
24    if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
25        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
26                       "recv: eof:%d, avail:%d, err:%d",
27                       rev->pending_eof, rev->available, rev->kq_errno);
28
29        if (rev->available == 0) {
30            if (rev->pending_eof) {
31                rev->ready = 0;
32                rev->eof = 1;
33
34                if (rev->kq_errno) {
35                    rev->error = 1;
36                    ngx_set_socket_errno(rev->kq_errno);
37
38                    return ngx_connection_error(c, rev->kq_errno,
39                               "kevent() reported about an closed connection");
40                }
41
42                return 0;
43
44            } else {
45                rev->ready = 0;
46                return NGX_AGAIN;
47            }
48        }
49    }
50
51#endif
52
53#if (NGX_HAVE_EPOLLRDHUP)
54
55    if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
56        ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
57                       "recv: eof:%d, avail:%d",
58                       rev->pending_eof, rev->available);
59
60        if (!rev->available && !rev->pending_eof) {
61            rev->ready = 0;
62            return NGX_AGAIN;
63        }
64    }
65
66#endif
67
68    do {
69        n = recv(c->fd, buf, size, 0);
70
71        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
72                       "recv: fd:%d %z of %uz", c->fd, n, size);
73
74        if (n == 0) {
75            rev->ready = 0;
76            rev->eof = 1;
77
78#if (NGX_HAVE_KQUEUE)
79
80            /*
81             * on FreeBSD recv() may return 0 on closed socket
82             * even if kqueue reported about available data
83             */
84
85            if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
86                rev->available = 0;
87            }
88
89#endif
90
91            return 0;
92        }
93
94        if (n > 0) {
95
96#if (NGX_HAVE_KQUEUE)
97
98            if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
99                rev->available -= n;
100
101                /*
102                 * rev->available may be negative here because some additional
103                 * bytes may be received between kevent() and recv()
104                 */
105
106                if (rev->available <= 0) {
107                    if (!rev->pending_eof) {
108                        rev->ready = 0;
109                    }
110
111                    rev->available = 0;
112                }
113
114                return n;
115            }
116
117#endif
118
119#if (NGX_HAVE_EPOLLRDHUP)
120
121            if ((ngx_event_flags & NGX_USE_EPOLL_EVENT)
122                && ngx_use_epoll_rdhup)
123            {
124                if ((size_t) n < size) {
125                    if (!rev->pending_eof) {
126                        rev->ready = 0;
127                    }
128
129                    rev->available = 0;
130                }
131
132                return n;
133            }
134
135#endif
136
137            if ((size_t) n < size
138                && !(ngx_event_flags & NGX_USE_GREEDY_EVENT))
139            {
140                rev->ready = 0;
141            }
142
143            return n;
144        }
145
146        err = ngx_socket_errno;
147
148        if (err == NGX_EAGAIN || err == NGX_EINTR) {
149            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
150                           "recv() not ready");
151            n = NGX_AGAIN;
152
153        } else {
154            n = ngx_connection_error(c, err, "recv() failed");
155            break;
156        }
157
158    } while (err == NGX_EINTR);
159
160    rev->ready = 0;
161
162    if (n == NGX_ERROR) {
163        rev->error = 1;
164    }
165
166    return n;
167}
168