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