Igor Sysoev | a983011 | 2003-05-19 16:39:14 +0000 | [diff] [blame] | 1 | |
Igor Sysoev | d90282d | 2004-09-28 08:34:51 +0000 | [diff] [blame] | 2 | /* |
Igor Sysoev | ff8da91 | 2004-09-29 16:00:49 +0000 | [diff] [blame] | 3 | * Copyright (C) Igor Sysoev |
Maxim Konovalov | f8d59e3 | 2012-01-18 15:07:43 +0000 | [diff] [blame] | 4 | * Copyright (C) Nginx, Inc. |
Igor Sysoev | d90282d | 2004-09-28 08:34:51 +0000 | [diff] [blame] | 5 | */ |
| 6 | |
| 7 | |
Igor Sysoev | a983011 | 2003-05-19 16:39:14 +0000 | [diff] [blame] | 8 | #include <ngx_config.h> |
| 9 | #include <ngx_core.h> |
Igor Sysoev | 239baac | 2003-06-11 15:28:34 +0000 | [diff] [blame] | 10 | #include <ngx_event.h> |
Igor Sysoev | a983011 | 2003-05-19 16:39:14 +0000 | [diff] [blame] | 11 | |
| 12 | |
Igor Sysoev | f690604 | 2004-11-25 16:17:31 +0000 | [diff] [blame] | 13 | #if (NGX_HAVE_KQUEUE) |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 14 | |
Igor Sysoev | 06187ce | 2007-12-01 20:25:32 +0000 | [diff] [blame] | 15 | ssize_t |
| 16 | ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) |
Igor Sysoev | a983011 | 2003-05-19 16:39:14 +0000 | [diff] [blame] | 17 | { |
| 18 | ssize_t n; |
Igor Sysoev | 7af6b16 | 2004-02-09 07:46:43 +0000 | [diff] [blame] | 19 | ngx_err_t err; |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 20 | ngx_event_t *rev; |
Igor Sysoev | a983011 | 2003-05-19 16:39:14 +0000 | [diff] [blame] | 21 | |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 22 | rev = c->read; |
Igor Sysoev | a983011 | 2003-05-19 16:39:14 +0000 | [diff] [blame] | 23 | |
Igor Sysoev | c0edbcc | 2004-10-21 15:34:38 +0000 | [diff] [blame] | 24 | if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { |
Igor Sysoev | 3c3ca17 | 2004-01-05 20:55:48 +0000 | [diff] [blame] | 25 | ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, |
| 26 | "recv: eof:%d, avail:%d, err:%d", |
Igor Sysoev | 98c1cf1 | 2004-07-02 15:54:34 +0000 | [diff] [blame] | 27 | rev->pending_eof, rev->available, rev->kq_errno); |
Igor Sysoev | a983011 | 2003-05-19 16:39:14 +0000 | [diff] [blame] | 28 | |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 29 | if (rev->available == 0) { |
Igor Sysoev | cdc4630 | 2005-12-07 14:51:31 +0000 | [diff] [blame] | 30 | if (rev->pending_eof) { |
Igor Sysoev | d404c97 | 2003-10-16 20:19:16 +0000 | [diff] [blame] | 31 | rev->ready = 0; |
Igor Sysoev | ab0c4f5 | 2003-10-28 15:45:41 +0000 | [diff] [blame] | 32 | rev->eof = 1; |
| 33 | |
| 34 | if (rev->kq_errno) { |
| 35 | rev->error = 1; |
| 36 | ngx_set_socket_errno(rev->kq_errno); |
Igor Sysoev | 3c3ca17 | 2004-01-05 20:55:48 +0000 | [diff] [blame] | 37 | |
Igor Sysoev | e503539 | 2005-08-30 10:55:07 +0000 | [diff] [blame] | 38 | return ngx_connection_error(c, rev->kq_errno, |
| 39 | "kevent() reported about an closed connection"); |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 40 | } |
Igor Sysoev | ab0c4f5 | 2003-10-28 15:45:41 +0000 | [diff] [blame] | 41 | |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 42 | return 0; |
Igor Sysoev | cdc4630 | 2005-12-07 14:51:31 +0000 | [diff] [blame] | 43 | |
| 44 | } else { |
Igor Sysoev | c463ece | 2008-01-31 15:36:33 +0000 | [diff] [blame] | 45 | rev->ready = 0; |
Igor Sysoev | cdc4630 | 2005-12-07 14:51:31 +0000 | [diff] [blame] | 46 | return NGX_AGAIN; |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 47 | } |
Igor Sysoev | a983011 | 2003-05-19 16:39:14 +0000 | [diff] [blame] | 48 | } |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 49 | } |
Igor Sysoev | a983011 | 2003-05-19 16:39:14 +0000 | [diff] [blame] | 50 | |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 51 | do { |
Igor Sysoev | a983011 | 2003-05-19 16:39:14 +0000 | [diff] [blame] | 52 | n = recv(c->fd, buf, size, 0); |
| 53 | |
Igor Sysoev | 7af6b16 | 2004-02-09 07:46:43 +0000 | [diff] [blame] | 54 | ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, |
| 55 | "recv: fd:%d %d of %d", c->fd, n, size); |
Igor Sysoev | a983011 | 2003-05-19 16:39:14 +0000 | [diff] [blame] | 56 | |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 57 | if (n >= 0) { |
Igor Sysoev | c0edbcc | 2004-10-21 15:34:38 +0000 | [diff] [blame] | 58 | if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 59 | rev->available -= n; |
Igor Sysoev | ab0c4f5 | 2003-10-28 15:45:41 +0000 | [diff] [blame] | 60 | |
| 61 | /* |
Igor Sysoev | d3283ff | 2005-12-05 13:18:09 +0000 | [diff] [blame] | 62 | * rev->available may be negative here because some additional |
Igor Sysoev | cdc4630 | 2005-12-07 14:51:31 +0000 | [diff] [blame] | 63 | * bytes may be received between kevent() and recv() |
Igor Sysoev | ab0c4f5 | 2003-10-28 15:45:41 +0000 | [diff] [blame] | 64 | */ |
| 65 | |
Igor Sysoev | 0a280a3 | 2003-10-12 16:49:16 +0000 | [diff] [blame] | 66 | if (rev->available <= 0) { |
Igor Sysoev | 98c1cf1 | 2004-07-02 15:54:34 +0000 | [diff] [blame] | 67 | if (!rev->pending_eof) { |
Igor Sysoev | d404c97 | 2003-10-16 20:19:16 +0000 | [diff] [blame] | 68 | rev->ready = 0; |
| 69 | } |
| 70 | |
Igor Sysoev | 0a280a3 | 2003-10-12 16:49:16 +0000 | [diff] [blame] | 71 | if (rev->available < 0) { |
| 72 | rev->available = 0; |
| 73 | } |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 74 | } |
Igor Sysoev | a983011 | 2003-05-19 16:39:14 +0000 | [diff] [blame] | 75 | |
Igor Sysoev | 9e58019 | 2006-02-01 18:22:15 +0000 | [diff] [blame] | 76 | if (n == 0) { |
| 77 | |
| 78 | /* |
| 79 | * on FreeBSD recv() may return 0 on closed socket |
| 80 | * even if kqueue reported about available data |
| 81 | */ |
| 82 | |
Valentin Bartenev | cf08ba7 | 2013-09-05 16:53:02 +0400 | [diff] [blame] | 83 | rev->ready = 0; |
Igor Sysoev | 9e58019 | 2006-02-01 18:22:15 +0000 | [diff] [blame] | 84 | rev->eof = 1; |
| 85 | rev->available = 0; |
| 86 | } |
| 87 | |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 88 | return n; |
| 89 | } |
Igor Sysoev | a983011 | 2003-05-19 16:39:14 +0000 | [diff] [blame] | 90 | |
Valentin Bartenev | 615d558 | 2013-07-13 03:24:30 +0400 | [diff] [blame] | 91 | if ((size_t) n < size |
| 92 | && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) |
| 93 | { |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 94 | rev->ready = 0; |
| 95 | } |
Igor Sysoev | a983011 | 2003-05-19 16:39:14 +0000 | [diff] [blame] | 96 | |
Igor Sysoev | ab0c4f5 | 2003-10-28 15:45:41 +0000 | [diff] [blame] | 97 | if (n == 0) { |
| 98 | rev->eof = 1; |
| 99 | } |
| 100 | |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 101 | return n; |
Igor Sysoev | a983011 | 2003-05-19 16:39:14 +0000 | [diff] [blame] | 102 | } |
| 103 | |
Igor Sysoev | 7af6b16 | 2004-02-09 07:46:43 +0000 | [diff] [blame] | 104 | err = ngx_socket_errno; |
Igor Sysoev | a983011 | 2003-05-19 16:39:14 +0000 | [diff] [blame] | 105 | |
Igor Sysoev | 7af6b16 | 2004-02-09 07:46:43 +0000 | [diff] [blame] | 106 | if (err == NGX_EAGAIN || err == NGX_EINTR) { |
Igor Sysoev | 54498db | 2004-02-11 17:08:49 +0000 | [diff] [blame] | 107 | ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, |
Igor Sysoev | 7af6b16 | 2004-02-09 07:46:43 +0000 | [diff] [blame] | 108 | "recv() not ready"); |
| 109 | n = NGX_AGAIN; |
Igor Sysoev | a983011 | 2003-05-19 16:39:14 +0000 | [diff] [blame] | 110 | |
Igor Sysoev | 7af6b16 | 2004-02-09 07:46:43 +0000 | [diff] [blame] | 111 | } else { |
| 112 | n = ngx_connection_error(c, err, "recv() failed"); |
| 113 | break; |
| 114 | } |
| 115 | |
| 116 | } while (err == NGX_EINTR); |
Igor Sysoev | 0b2b4cc | 2003-11-18 08:04:34 +0000 | [diff] [blame] | 117 | |
| 118 | rev->ready = 0; |
| 119 | |
Igor Sysoev | aa6936e | 2010-06-23 16:34:54 +0000 | [diff] [blame] | 120 | if (n == NGX_ERROR) { |
Igor Sysoev | 7f9d894 | 2003-11-14 07:20:34 +0000 | [diff] [blame] | 121 | rev->error = 1; |
| 122 | } |
| 123 | |
Igor Sysoev | a983011 | 2003-05-19 16:39:14 +0000 | [diff] [blame] | 124 | return n; |
| 125 | } |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 126 | |
Igor Sysoev | f690604 | 2004-11-25 16:17:31 +0000 | [diff] [blame] | 127 | #else /* ! NGX_HAVE_KQUEUE */ |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 128 | |
Igor Sysoev | 06187ce | 2007-12-01 20:25:32 +0000 | [diff] [blame] | 129 | ssize_t |
| 130 | ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 131 | { |
| 132 | ssize_t n; |
Igor Sysoev | 7af6b16 | 2004-02-09 07:46:43 +0000 | [diff] [blame] | 133 | ngx_err_t err; |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 134 | ngx_event_t *rev; |
| 135 | |
| 136 | rev = c->read; |
| 137 | |
| 138 | do { |
| 139 | n = recv(c->fd, buf, size, 0); |
| 140 | |
Igor Sysoev | 7af6b16 | 2004-02-09 07:46:43 +0000 | [diff] [blame] | 141 | ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, |
| 142 | "recv: fd:%d %d of %d", c->fd, n, size); |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 143 | |
Igor Sysoev | 4cec79f | 2004-04-28 06:14:50 +0000 | [diff] [blame] | 144 | if (n == 0) { |
| 145 | rev->ready = 0; |
| 146 | rev->eof = 1; |
| 147 | return n; |
Igor Sysoev | ab0c4f5 | 2003-10-28 15:45:41 +0000 | [diff] [blame] | 148 | |
Igor Sysoev | 4cec79f | 2004-04-28 06:14:50 +0000 | [diff] [blame] | 149 | } else if (n > 0) { |
| 150 | |
| 151 | if ((size_t) n < size |
Igor Sysoev | c0edbcc | 2004-10-21 15:34:38 +0000 | [diff] [blame] | 152 | && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) |
Igor Sysoev | 4cec79f | 2004-04-28 06:14:50 +0000 | [diff] [blame] | 153 | { |
| 154 | rev->ready = 0; |
Igor Sysoev | ab0c4f5 | 2003-10-28 15:45:41 +0000 | [diff] [blame] | 155 | } |
| 156 | |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 157 | return n; |
| 158 | } |
| 159 | |
Igor Sysoev | 7af6b16 | 2004-02-09 07:46:43 +0000 | [diff] [blame] | 160 | err = ngx_socket_errno; |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 161 | |
Igor Sysoev | 7af6b16 | 2004-02-09 07:46:43 +0000 | [diff] [blame] | 162 | if (err == NGX_EAGAIN || err == NGX_EINTR) { |
Igor Sysoev | 54498db | 2004-02-11 17:08:49 +0000 | [diff] [blame] | 163 | ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, |
Igor Sysoev | 7af6b16 | 2004-02-09 07:46:43 +0000 | [diff] [blame] | 164 | "recv() not ready"); |
| 165 | n = NGX_AGAIN; |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 166 | |
Igor Sysoev | 7af6b16 | 2004-02-09 07:46:43 +0000 | [diff] [blame] | 167 | } else { |
| 168 | n = ngx_connection_error(c, err, "recv() failed"); |
| 169 | break; |
| 170 | } |
| 171 | |
| 172 | } while (err == NGX_EINTR); |
Igor Sysoev | 0b2b4cc | 2003-11-18 08:04:34 +0000 | [diff] [blame] | 173 | |
| 174 | rev->ready = 0; |
| 175 | |
Igor Sysoev | aa6936e | 2010-06-23 16:34:54 +0000 | [diff] [blame] | 176 | if (n == NGX_ERROR) { |
Igor Sysoev | 7f9d894 | 2003-11-14 07:20:34 +0000 | [diff] [blame] | 177 | rev->error = 1; |
| 178 | } |
| 179 | |
Igor Sysoev | 6253ca1 | 2003-05-27 12:18:54 +0000 | [diff] [blame] | 180 | return n; |
| 181 | } |
| 182 | |
Igor Sysoev | f690604 | 2004-11-25 16:17:31 +0000 | [diff] [blame] | 183 | #endif /* NGX_HAVE_KQUEUE */ |