xref: /f-stack/app/nginx-1.16.1/src/os/unix/ngx_recv.c (revision 3da8d17d)
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 
13 ssize_t
ngx_unix_recv(ngx_connection_t * c,u_char * buf,size_t size)14 ngx_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) || (NGX_HAVE_FSTACK)
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) || (NGX_HAVE_FSTACK)
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) || (NGX_HAVE_FSTACK)
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