Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +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 |
Igor Sysoev | d90282d | 2004-09-28 08:34:51 +0000 | [diff] [blame] | 4 | */ |
| 5 | |
| 6 | |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 7 | #include <ngx_config.h> |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 8 | #include <ngx_core.h> |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 9 | #include <ngx_event.h> |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 10 | |
| 11 | |
Igor Sysoev | 31eb8c0 | 2005-09-23 11:02:22 +0000 | [diff] [blame] | 12 | static void ngx_close_posted_connection(ngx_connection_t *c); |
| 13 | |
| 14 | |
| 15 | void |
| 16 | ngx_event_acceptex(ngx_event_t *rev) |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 17 | { |
| 18 | ngx_connection_t *c; |
| 19 | |
Igor Sysoev | 1b73583 | 2004-11-11 14:07:14 +0000 | [diff] [blame] | 20 | c = rev->data; |
| 21 | |
Igor Sysoev | 31eb8c0 | 2005-09-23 11:02:22 +0000 | [diff] [blame] | 22 | c->log->handler = ngx_accept_log_error; |
| 23 | |
Igor Sysoev | 1b73583 | 2004-11-11 14:07:14 +0000 | [diff] [blame] | 24 | ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "AcceptEx: %d", c->fd); |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 25 | |
Igor Sysoev | e4a2526 | 2003-06-06 14:59:20 +0000 | [diff] [blame] | 26 | if (rev->ovlp.error) { |
Igor Sysoev | 239baac | 2003-06-11 15:28:34 +0000 | [diff] [blame] | 27 | ngx_log_error(NGX_LOG_CRIT, c->log, rev->ovlp.error, |
Igor Sysoev | 1b73583 | 2004-11-11 14:07:14 +0000 | [diff] [blame] | 28 | "AcceptEx() %V failed", &c->listening->addr_text); |
Igor Sysoev | 1c10462 | 2003-06-03 15:42:58 +0000 | [diff] [blame] | 29 | return; |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 30 | } |
| 31 | |
Igor Sysoev | e4a2526 | 2003-06-06 14:59:20 +0000 | [diff] [blame] | 32 | /* SO_UPDATE_ACCEPT_CONTEXT is required for shutdown() to work */ |
Igor Sysoev | fa73aac | 2003-05-21 13:28:21 +0000 | [diff] [blame] | 33 | |
Igor Sysoev | 1c10462 | 2003-06-03 15:42:58 +0000 | [diff] [blame] | 34 | if (setsockopt(c->fd, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, |
Igor Sysoev | 1b73583 | 2004-11-11 14:07:14 +0000 | [diff] [blame] | 35 | (char *) &c->listening->fd, sizeof(ngx_socket_t)) == -1) |
Igor Sysoev | 1c10462 | 2003-06-03 15:42:58 +0000 | [diff] [blame] | 36 | { |
Igor Sysoev | 239baac | 2003-06-11 15:28:34 +0000 | [diff] [blame] | 37 | ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno, |
Igor Sysoev | 1b73583 | 2004-11-11 14:07:14 +0000 | [diff] [blame] | 38 | "setsockopt(SO_UPDATE_ACCEPT_CONTEXT) failed for %V", |
| 39 | &c->addr_text); |
Igor Sysoev | e4a2526 | 2003-06-06 14:59:20 +0000 | [diff] [blame] | 40 | } else { |
Igor Sysoev | 239baac | 2003-06-11 15:28:34 +0000 | [diff] [blame] | 41 | c->accept_context_updated = 1; |
Igor Sysoev | 1c10462 | 2003-06-03 15:42:58 +0000 | [diff] [blame] | 42 | } |
Igor Sysoev | fa73aac | 2003-05-21 13:28:21 +0000 | [diff] [blame] | 43 | |
Igor Sysoev | 239baac | 2003-06-11 15:28:34 +0000 | [diff] [blame] | 44 | getacceptexsockaddrs(c->buffer->pos, c->listening->post_accept_buffer_size, |
| 45 | c->listening->socklen + 16, |
| 46 | c->listening->socklen + 16, |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 47 | &c->local_sockaddr, &c->local_socklen, |
| 48 | &c->sockaddr, &c->socklen); |
| 49 | |
Igor Sysoev | 239baac | 2003-06-11 15:28:34 +0000 | [diff] [blame] | 50 | if (c->listening->post_accept_buffer_size) { |
| 51 | c->buffer->last += rev->available; |
| 52 | c->buffer->end = c->buffer->start |
| 53 | + c->listening->post_accept_buffer_size; |
| 54 | |
| 55 | } else { |
| 56 | c->buffer = NULL; |
| 57 | } |
| 58 | |
Igor Sysoev | 1b73583 | 2004-11-11 14:07:14 +0000 | [diff] [blame] | 59 | if (c->listening->addr_ntop) { |
| 60 | c->addr_text.data = ngx_palloc(c->pool, |
| 61 | c->listening->addr_text_max_len); |
| 62 | if (c->addr_text.data == NULL) { |
| 63 | /* TODO: close socket */ |
| 64 | return; |
| 65 | } |
| 66 | |
| 67 | c->addr_text.len = ngx_sock_ntop(c->listening->family, c->sockaddr, |
| 68 | c->addr_text.data, |
| 69 | c->listening->addr_text_max_len); |
| 70 | if (c->addr_text.len == 0) { |
| 71 | /* TODO: close socket */ |
| 72 | return; |
| 73 | } |
| 74 | } |
| 75 | |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 76 | ngx_event_post_acceptex(c->listening, 1); |
| 77 | |
Igor Sysoev | 7845223 | 2005-10-12 13:50:36 +0000 | [diff] [blame] | 78 | c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 79 | |
Igor Sysoev | 239baac | 2003-06-11 15:28:34 +0000 | [diff] [blame] | 80 | c->listening->handler(c); |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 81 | |
Igor Sysoev | 1c10462 | 2003-06-03 15:42:58 +0000 | [diff] [blame] | 82 | return; |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 83 | |
| 84 | } |
| 85 | |
| 86 | |
Igor Sysoev | 31eb8c0 | 2005-09-23 11:02:22 +0000 | [diff] [blame] | 87 | ngx_int_t |
| 88 | ngx_event_post_acceptex(ngx_listening_t *ls, ngx_uint_t n) |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 89 | { |
Igor Sysoev | ab9d5fd | 2004-03-05 08:34:24 +0000 | [diff] [blame] | 90 | u_long rcvd; |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 91 | ngx_err_t err; |
Igor Sysoev | 31eb8c0 | 2005-09-23 11:02:22 +0000 | [diff] [blame] | 92 | ngx_log_t *log; |
| 93 | ngx_uint_t i; |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 94 | ngx_event_t *rev, *wev; |
| 95 | ngx_socket_t s; |
| 96 | ngx_connection_t *c; |
| 97 | |
| 98 | for (i = 0; i < n; i++) { |
| 99 | |
| 100 | /* TODO: look up reused sockets */ |
| 101 | |
Igor Sysoev | 02025fd | 2005-01-18 13:03:58 +0000 | [diff] [blame] | 102 | s = ngx_socket(ls->family, ls->type, 0); |
Igor Sysoev | a536298 | 2004-03-04 07:04:55 +0000 | [diff] [blame] | 103 | |
Igor Sysoev | 31eb8c0 | 2005-09-23 11:02:22 +0000 | [diff] [blame] | 104 | ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &ls->log, 0, |
Igor Sysoev | 1b73583 | 2004-11-11 14:07:14 +0000 | [diff] [blame] | 105 | ngx_socket_n " s:%d", s); |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 106 | |
| 107 | if (s == -1) { |
Igor Sysoev | 31eb8c0 | 2005-09-23 11:02:22 +0000 | [diff] [blame] | 108 | ngx_log_error(NGX_LOG_ALERT, &ls->log, ngx_socket_errno, |
| 109 | ngx_socket_n " failed"); |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 110 | |
| 111 | return NGX_ERROR; |
| 112 | } |
| 113 | |
Igor Sysoev | 31eb8c0 | 2005-09-23 11:02:22 +0000 | [diff] [blame] | 114 | c = ngx_get_connection(s, &ls->log); |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 115 | |
Igor Sysoev | 31eb8c0 | 2005-09-23 11:02:22 +0000 | [diff] [blame] | 116 | if (c == NULL) { |
| 117 | return NGX_ERROR; |
Igor Sysoev | 239baac | 2003-06-11 15:28:34 +0000 | [diff] [blame] | 118 | } |
| 119 | |
Igor Sysoev | 31eb8c0 | 2005-09-23 11:02:22 +0000 | [diff] [blame] | 120 | c->pool = ngx_create_pool(ls->pool_size, &ls->log); |
| 121 | if (c->pool == NULL) { |
| 122 | ngx_close_posted_connection(c); |
| 123 | return NGX_ERROR; |
| 124 | } |
| 125 | |
| 126 | log = ngx_palloc(c->pool, sizeof(ngx_log_t)); |
| 127 | if (log == NULL) { |
| 128 | ngx_close_posted_connection(c); |
| 129 | return NGX_ERROR; |
| 130 | } |
| 131 | |
| 132 | c->buffer = ngx_create_temp_buf(c->pool, ls->post_accept_buffer_size |
| 133 | + 2 * (ls->socklen + 16)); |
| 134 | if (c->buffer == NULL) { |
| 135 | ngx_close_posted_connection(c); |
| 136 | return NGX_ERROR; |
| 137 | } |
| 138 | |
| 139 | c->local_sockaddr = ngx_palloc(c->pool, ls->socklen); |
| 140 | if (c->local_sockaddr == NULL) { |
| 141 | ngx_close_posted_connection(c); |
| 142 | return NGX_ERROR; |
| 143 | } |
| 144 | |
| 145 | c->sockaddr = ngx_palloc(c->pool, ls->socklen); |
| 146 | if (c->sockaddr == NULL) { |
| 147 | ngx_close_posted_connection(c); |
| 148 | return NGX_ERROR; |
| 149 | } |
| 150 | |
| 151 | *log = ls->log; |
| 152 | c->log = log; |
| 153 | |
| 154 | c->recv = ngx_recv; |
| 155 | c->send = ngx_send; |
Igor Sysoev | 0e5dc5c | 2005-11-15 13:30:52 +0000 | [diff] [blame] | 156 | c->recv_chain = ngx_recv_chain; |
Igor Sysoev | 31eb8c0 | 2005-09-23 11:02:22 +0000 | [diff] [blame] | 157 | c->send_chain = ngx_send_chain; |
| 158 | |
| 159 | c->unexpected_eof = 1; |
| 160 | |
Igor Sysoev | 31eb8c0 | 2005-09-23 11:02:22 +0000 | [diff] [blame] | 161 | c->listening = ls; |
| 162 | |
Igor Sysoev | 7845223 | 2005-10-12 13:50:36 +0000 | [diff] [blame] | 163 | rev = c->read; |
| 164 | wev = c->write; |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 165 | |
| 166 | rev->ovlp.event = rev; |
| 167 | wev->ovlp.event = wev; |
Igor Sysoev | 899b44e | 2005-05-12 14:58:06 +0000 | [diff] [blame] | 168 | rev->handler = ngx_event_acceptex; |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 169 | |
Igor Sysoev | 1b73583 | 2004-11-11 14:07:14 +0000 | [diff] [blame] | 170 | rev->ready = 1; |
Igor Sysoev | 1b73583 | 2004-11-11 14:07:14 +0000 | [diff] [blame] | 171 | wev->ready = 1; |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 172 | |
Igor Sysoev | 31eb8c0 | 2005-09-23 11:02:22 +0000 | [diff] [blame] | 173 | rev->log = c->log; |
| 174 | wev->log = c->log; |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 175 | |
Igor Sysoev | e4a2526 | 2003-06-06 14:59:20 +0000 | [diff] [blame] | 176 | if (ngx_add_event(rev, 0, NGX_IOCP_IO) == NGX_ERROR) { |
Igor Sysoev | 31eb8c0 | 2005-09-23 11:02:22 +0000 | [diff] [blame] | 177 | ngx_close_posted_connection(c); |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 178 | return NGX_ERROR; |
| 179 | } |
| 180 | |
Igor Sysoev | 239baac | 2003-06-11 15:28:34 +0000 | [diff] [blame] | 181 | if (acceptex(ls->fd, s, c->buffer->pos, ls->post_accept_buffer_size, |
| 182 | ls->socklen + 16, ls->socklen + 16, |
| 183 | &rcvd, (LPOVERLAPPED) &rev->ovlp) == 0) |
| 184 | { |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 185 | |
| 186 | err = ngx_socket_errno; |
Igor Sysoev | 239baac | 2003-06-11 15:28:34 +0000 | [diff] [blame] | 187 | if (err != WSA_IO_PENDING) { |
Igor Sysoev | 31eb8c0 | 2005-09-23 11:02:22 +0000 | [diff] [blame] | 188 | ngx_log_error(NGX_LOG_ALERT, &ls->log, err, |
Igor Sysoev | c2068d0 | 2005-10-19 12:33:58 +0000 | [diff] [blame] | 189 | "AcceptEx() %V falied", &ls->addr_text); |
Igor Sysoev | 239baac | 2003-06-11 15:28:34 +0000 | [diff] [blame] | 190 | |
Igor Sysoev | 31eb8c0 | 2005-09-23 11:02:22 +0000 | [diff] [blame] | 191 | ngx_close_posted_connection(c); |
Igor Sysoev | 239baac | 2003-06-11 15:28:34 +0000 | [diff] [blame] | 192 | return NGX_ERROR; |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 193 | } |
Igor Sysoev | 7300977 | 2003-02-06 17:21:13 +0000 | [diff] [blame] | 194 | } |
| 195 | } |
| 196 | |
| 197 | return NGX_OK; |
| 198 | } |
Igor Sysoev | 31eb8c0 | 2005-09-23 11:02:22 +0000 | [diff] [blame] | 199 | |
| 200 | |
| 201 | static void |
| 202 | ngx_close_posted_connection(ngx_connection_t *c) |
| 203 | { |
| 204 | ngx_socket_t fd; |
| 205 | |
| 206 | ngx_free_connection(c); |
| 207 | |
| 208 | fd = c->fd; |
| 209 | c->fd = (ngx_socket_t) -1; |
| 210 | |
| 211 | if (ngx_close_socket(fd) == -1) { |
| 212 | ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, |
| 213 | ngx_close_socket_n " failed"); |
| 214 | } |
| 215 | |
| 216 | if (c->pool) { |
| 217 | ngx_destroy_pool(c->pool); |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | |
| 222 | u_char * |
| 223 | ngx_acceptex_log_error(ngx_log_t *log, u_char *buf, size_t len) |
| 224 | { |
| 225 | return ngx_snprintf(buf, len, " while posting AcceptEx() on %V", log->data); |
| 226 | } |