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