1e18a033bSKonstantin Ananyev
2e18a033bSKonstantin Ananyev/*
3e18a033bSKonstantin Ananyev * Copyright (C) Maxim Dounin
4e18a033bSKonstantin Ananyev * Copyright (C) Nginx, Inc.
5e18a033bSKonstantin Ananyev */
6e18a033bSKonstantin Ananyev
7e18a033bSKonstantin Ananyev
8e18a033bSKonstantin Ananyev#include <ngx_config.h>
9e18a033bSKonstantin Ananyev#include <ngx_core.h>
10e18a033bSKonstantin Ananyev#include <ngx_http.h>
11e18a033bSKonstantin Ananyev
12e18a033bSKonstantin Ananyev
13e18a033bSKonstantin Ananyevtypedef struct {
14e18a033bSKonstantin Ananyev    ngx_uint_t                         max_cached;
15e18a033bSKonstantin Ananyev
16e18a033bSKonstantin Ananyev    ngx_queue_t                        cache;
17e18a033bSKonstantin Ananyev    ngx_queue_t                        free;
18e18a033bSKonstantin Ananyev
19e18a033bSKonstantin Ananyev    ngx_http_upstream_init_pt          original_init_upstream;
20e18a033bSKonstantin Ananyev    ngx_http_upstream_init_peer_pt     original_init_peer;
21e18a033bSKonstantin Ananyev
22e18a033bSKonstantin Ananyev} ngx_http_upstream_keepalive_srv_conf_t;
23e18a033bSKonstantin Ananyev
24e18a033bSKonstantin Ananyev
25e18a033bSKonstantin Ananyevtypedef struct {
26e18a033bSKonstantin Ananyev    ngx_http_upstream_keepalive_srv_conf_t  *conf;
27e18a033bSKonstantin Ananyev
28e18a033bSKonstantin Ananyev    ngx_queue_t                        queue;
29e18a033bSKonstantin Ananyev    ngx_connection_t                  *connection;
30e18a033bSKonstantin Ananyev
31e18a033bSKonstantin Ananyev    socklen_t                          socklen;
32e18a033bSKonstantin Ananyev    ngx_sockaddr_t                     sockaddr;
33e18a033bSKonstantin Ananyev
34e18a033bSKonstantin Ananyev} ngx_http_upstream_keepalive_cache_t;
35e18a033bSKonstantin Ananyev
36e18a033bSKonstantin Ananyev
37e18a033bSKonstantin Ananyevtypedef struct {
38e18a033bSKonstantin Ananyev    ngx_http_upstream_keepalive_srv_conf_t  *conf;
39e18a033bSKonstantin Ananyev
40e18a033bSKonstantin Ananyev    ngx_http_upstream_t               *upstream;
41e18a033bSKonstantin Ananyev
42e18a033bSKonstantin Ananyev    void                              *data;
43e18a033bSKonstantin Ananyev
44e18a033bSKonstantin Ananyev    ngx_event_get_peer_pt              original_get_peer;
45e18a033bSKonstantin Ananyev    ngx_event_free_peer_pt             original_free_peer;
46e18a033bSKonstantin Ananyev
47e18a033bSKonstantin Ananyev#if (NGX_HTTP_SSL)
48e18a033bSKonstantin Ananyev    ngx_event_set_peer_session_pt      original_set_session;
49e18a033bSKonstantin Ananyev    ngx_event_save_peer_session_pt     original_save_session;
50e18a033bSKonstantin Ananyev#endif
51e18a033bSKonstantin Ananyev
52e18a033bSKonstantin Ananyev} ngx_http_upstream_keepalive_peer_data_t;
53e18a033bSKonstantin Ananyev
54e18a033bSKonstantin Ananyev
55e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_upstream_init_keepalive_peer(ngx_http_request_t *r,
56e18a033bSKonstantin Ananyev    ngx_http_upstream_srv_conf_t *us);
57e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc,
58e18a033bSKonstantin Ananyev    void *data);
59e18a033bSKonstantin Ananyevstatic void ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc,
60e18a033bSKonstantin Ananyev    void *data, ngx_uint_t state);
61e18a033bSKonstantin Ananyev
62e18a033bSKonstantin Ananyevstatic void ngx_http_upstream_keepalive_dummy_handler(ngx_event_t *ev);
63e18a033bSKonstantin Ananyevstatic void ngx_http_upstream_keepalive_close_handler(ngx_event_t *ev);
64e18a033bSKonstantin Ananyevstatic void ngx_http_upstream_keepalive_close(ngx_connection_t *c);
65e18a033bSKonstantin Ananyev
66e18a033bSKonstantin Ananyev#if (NGX_HTTP_SSL)
67e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_upstream_keepalive_set_session(
68e18a033bSKonstantin Ananyev    ngx_peer_connection_t *pc, void *data);
69e18a033bSKonstantin Ananyevstatic void ngx_http_upstream_keepalive_save_session(ngx_peer_connection_t *pc,
70e18a033bSKonstantin Ananyev    void *data);
71e18a033bSKonstantin Ananyev#endif
72e18a033bSKonstantin Ananyev
73e18a033bSKonstantin Ananyevstatic void *ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf);
74e18a033bSKonstantin Ananyevstatic char *ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd,
75e18a033bSKonstantin Ananyev    void *conf);
76e18a033bSKonstantin Ananyev
77e18a033bSKonstantin Ananyev
78e18a033bSKonstantin Ananyevstatic ngx_command_t  ngx_http_upstream_keepalive_commands[] = {
79e18a033bSKonstantin Ananyev
80e18a033bSKonstantin Ananyev    { ngx_string("keepalive"),
81e18a033bSKonstantin Ananyev      NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1,
82e18a033bSKonstantin Ananyev      ngx_http_upstream_keepalive,
83e18a033bSKonstantin Ananyev      NGX_HTTP_SRV_CONF_OFFSET,
84e18a033bSKonstantin Ananyev      0,
85e18a033bSKonstantin Ananyev      NULL },
86e18a033bSKonstantin Ananyev
87e18a033bSKonstantin Ananyev      ngx_null_command
88e18a033bSKonstantin Ananyev};
89e18a033bSKonstantin Ananyev
90e18a033bSKonstantin Ananyev
91e18a033bSKonstantin Ananyevstatic ngx_http_module_t  ngx_http_upstream_keepalive_module_ctx = {
92e18a033bSKonstantin Ananyev    NULL,                                  /* preconfiguration */
93e18a033bSKonstantin Ananyev    NULL,                                  /* postconfiguration */
94e18a033bSKonstantin Ananyev
95e18a033bSKonstantin Ananyev    NULL,                                  /* create main configuration */
96e18a033bSKonstantin Ananyev    NULL,                                  /* init main configuration */
97e18a033bSKonstantin Ananyev
98e18a033bSKonstantin Ananyev    ngx_http_upstream_keepalive_create_conf, /* create server configuration */
99e18a033bSKonstantin Ananyev    NULL,                                  /* merge server configuration */
100e18a033bSKonstantin Ananyev
101e18a033bSKonstantin Ananyev    NULL,                                  /* create location configuration */
102e18a033bSKonstantin Ananyev    NULL                                   /* merge location configuration */
103e18a033bSKonstantin Ananyev};
104e18a033bSKonstantin Ananyev
105e18a033bSKonstantin Ananyev
106e18a033bSKonstantin Ananyevngx_module_t  ngx_http_upstream_keepalive_module = {
107e18a033bSKonstantin Ananyev    NGX_MODULE_V1,
108e18a033bSKonstantin Ananyev    &ngx_http_upstream_keepalive_module_ctx, /* module context */
109e18a033bSKonstantin Ananyev    ngx_http_upstream_keepalive_commands,    /* module directives */
110e18a033bSKonstantin Ananyev    NGX_HTTP_MODULE,                       /* module type */
111e18a033bSKonstantin Ananyev    NULL,                                  /* init master */
112e18a033bSKonstantin Ananyev    NULL,                                  /* init module */
113e18a033bSKonstantin Ananyev    NULL,                                  /* init process */
114e18a033bSKonstantin Ananyev    NULL,                                  /* init thread */
115e18a033bSKonstantin Ananyev    NULL,                                  /* exit thread */
116e18a033bSKonstantin Ananyev    NULL,                                  /* exit process */
117e18a033bSKonstantin Ananyev    NULL,                                  /* exit master */
118e18a033bSKonstantin Ananyev    NGX_MODULE_V1_PADDING
119e18a033bSKonstantin Ananyev};
120e18a033bSKonstantin Ananyev
121e18a033bSKonstantin Ananyev
122e18a033bSKonstantin Ananyevstatic ngx_int_t
123e18a033bSKonstantin Ananyevngx_http_upstream_init_keepalive(ngx_conf_t *cf,
124e18a033bSKonstantin Ananyev    ngx_http_upstream_srv_conf_t *us)
125e18a033bSKonstantin Ananyev{
126e18a033bSKonstantin Ananyev    ngx_uint_t                               i;
127e18a033bSKonstantin Ananyev    ngx_http_upstream_keepalive_srv_conf_t  *kcf;
128e18a033bSKonstantin Ananyev    ngx_http_upstream_keepalive_cache_t     *cached;
129e18a033bSKonstantin Ananyev
130e18a033bSKonstantin Ananyev    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0,
131e18a033bSKonstantin Ananyev                   "init keepalive");
132e18a033bSKonstantin Ananyev
133e18a033bSKonstantin Ananyev    kcf = ngx_http_conf_upstream_srv_conf(us,
134e18a033bSKonstantin Ananyev                                          ngx_http_upstream_keepalive_module);
135e18a033bSKonstantin Ananyev
136e18a033bSKonstantin Ananyev    if (kcf->original_init_upstream(cf, us) != NGX_OK) {
137e18a033bSKonstantin Ananyev        return NGX_ERROR;
138e18a033bSKonstantin Ananyev    }
139e18a033bSKonstantin Ananyev
140e18a033bSKonstantin Ananyev    kcf->original_init_peer = us->peer.init;
141e18a033bSKonstantin Ananyev
142e18a033bSKonstantin Ananyev    us->peer.init = ngx_http_upstream_init_keepalive_peer;
143e18a033bSKonstantin Ananyev
144e18a033bSKonstantin Ananyev    /* allocate cache items and add to free queue */
145e18a033bSKonstantin Ananyev
146e18a033bSKonstantin Ananyev    cached = ngx_pcalloc(cf->pool,
147e18a033bSKonstantin Ananyev                sizeof(ngx_http_upstream_keepalive_cache_t) * kcf->max_cached);
148e18a033bSKonstantin Ananyev    if (cached == NULL) {
149e18a033bSKonstantin Ananyev        return NGX_ERROR;
150e18a033bSKonstantin Ananyev    }
151e18a033bSKonstantin Ananyev
152e18a033bSKonstantin Ananyev    ngx_queue_init(&kcf->cache);
153e18a033bSKonstantin Ananyev    ngx_queue_init(&kcf->free);
154e18a033bSKonstantin Ananyev
155e18a033bSKonstantin Ananyev    for (i = 0; i < kcf->max_cached; i++) {
156e18a033bSKonstantin Ananyev        ngx_queue_insert_head(&kcf->free, &cached[i].queue);
157e18a033bSKonstantin Ananyev        cached[i].conf = kcf;
158e18a033bSKonstantin Ananyev    }
159e18a033bSKonstantin Ananyev
160e18a033bSKonstantin Ananyev    return NGX_OK;
161e18a033bSKonstantin Ananyev}
162e18a033bSKonstantin Ananyev
163e18a033bSKonstantin Ananyev
164e18a033bSKonstantin Ananyevstatic ngx_int_t
165e18a033bSKonstantin Ananyevngx_http_upstream_init_keepalive_peer(ngx_http_request_t *r,
166e18a033bSKonstantin Ananyev    ngx_http_upstream_srv_conf_t *us)
167e18a033bSKonstantin Ananyev{
168e18a033bSKonstantin Ananyev    ngx_http_upstream_keepalive_peer_data_t  *kp;
169e18a033bSKonstantin Ananyev    ngx_http_upstream_keepalive_srv_conf_t   *kcf;
170e18a033bSKonstantin Ananyev
171e18a033bSKonstantin Ananyev    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
172e18a033bSKonstantin Ananyev                   "init keepalive peer");
173e18a033bSKonstantin Ananyev
174e18a033bSKonstantin Ananyev    kcf = ngx_http_conf_upstream_srv_conf(us,
175e18a033bSKonstantin Ananyev                                          ngx_http_upstream_keepalive_module);
176e18a033bSKonstantin Ananyev
177e18a033bSKonstantin Ananyev    kp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_keepalive_peer_data_t));
178e18a033bSKonstantin Ananyev    if (kp == NULL) {
179e18a033bSKonstantin Ananyev        return NGX_ERROR;
180e18a033bSKonstantin Ananyev    }
181e18a033bSKonstantin Ananyev
182e18a033bSKonstantin Ananyev    if (kcf->original_init_peer(r, us) != NGX_OK) {
183e18a033bSKonstantin Ananyev        return NGX_ERROR;
184e18a033bSKonstantin Ananyev    }
185e18a033bSKonstantin Ananyev
186e18a033bSKonstantin Ananyev    kp->conf = kcf;
187e18a033bSKonstantin Ananyev    kp->upstream = r->upstream;
188e18a033bSKonstantin Ananyev    kp->data = r->upstream->peer.data;
189e18a033bSKonstantin Ananyev    kp->original_get_peer = r->upstream->peer.get;
190e18a033bSKonstantin Ananyev    kp->original_free_peer = r->upstream->peer.free;
191e18a033bSKonstantin Ananyev
192e18a033bSKonstantin Ananyev    r->upstream->peer.data = kp;
193e18a033bSKonstantin Ananyev    r->upstream->peer.get = ngx_http_upstream_get_keepalive_peer;
194e18a033bSKonstantin Ananyev    r->upstream->peer.free = ngx_http_upstream_free_keepalive_peer;
195e18a033bSKonstantin Ananyev
196e18a033bSKonstantin Ananyev#if (NGX_HTTP_SSL)
197e18a033bSKonstantin Ananyev    kp->original_set_session = r->upstream->peer.set_session;
198e18a033bSKonstantin Ananyev    kp->original_save_session = r->upstream->peer.save_session;
199e18a033bSKonstantin Ananyev    r->upstream->peer.set_session = ngx_http_upstream_keepalive_set_session;
200e18a033bSKonstantin Ananyev    r->upstream->peer.save_session = ngx_http_upstream_keepalive_save_session;
201e18a033bSKonstantin Ananyev#endif
202e18a033bSKonstantin Ananyev
203e18a033bSKonstantin Ananyev    return NGX_OK;
204e18a033bSKonstantin Ananyev}
205e18a033bSKonstantin Ananyev
206e18a033bSKonstantin Ananyev
207e18a033bSKonstantin Ananyevstatic ngx_int_t
208e18a033bSKonstantin Ananyevngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc, void *data)
209e18a033bSKonstantin Ananyev{
210e18a033bSKonstantin Ananyev    ngx_http_upstream_keepalive_peer_data_t  *kp = data;
211e18a033bSKonstantin Ananyev    ngx_http_upstream_keepalive_cache_t      *item;
212e18a033bSKonstantin Ananyev
213e18a033bSKonstantin Ananyev    ngx_int_t          rc;
214e18a033bSKonstantin Ananyev    ngx_queue_t       *q, *cache;
215e18a033bSKonstantin Ananyev    ngx_connection_t  *c;
216e18a033bSKonstantin Ananyev
217e18a033bSKonstantin Ananyev    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
218e18a033bSKonstantin Ananyev                   "get keepalive peer");
219e18a033bSKonstantin Ananyev
220e18a033bSKonstantin Ananyev    /* ask balancer */
221e18a033bSKonstantin Ananyev
222e18a033bSKonstantin Ananyev    rc = kp->original_get_peer(pc, kp->data);
223e18a033bSKonstantin Ananyev
224e18a033bSKonstantin Ananyev    if (rc != NGX_OK) {
225e18a033bSKonstantin Ananyev        return rc;
226e18a033bSKonstantin Ananyev    }
227e18a033bSKonstantin Ananyev
228e18a033bSKonstantin Ananyev    /* search cache for suitable connection */
229e18a033bSKonstantin Ananyev
230e18a033bSKonstantin Ananyev    cache = &kp->conf->cache;
231e18a033bSKonstantin Ananyev
232e18a033bSKonstantin Ananyev    for (q = ngx_queue_head(cache);
233e18a033bSKonstantin Ananyev         q != ngx_queue_sentinel(cache);
234e18a033bSKonstantin Ananyev         q = ngx_queue_next(q))
235e18a033bSKonstantin Ananyev    {
236e18a033bSKonstantin Ananyev        item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue);
237e18a033bSKonstantin Ananyev        c = item->connection;
238e18a033bSKonstantin Ananyev
239e18a033bSKonstantin Ananyev        if (ngx_memn2cmp((u_char *) &item->sockaddr, (u_char *) pc->sockaddr,
240e18a033bSKonstantin Ananyev                         item->socklen, pc->socklen)
241e18a033bSKonstantin Ananyev            == 0)
242e18a033bSKonstantin Ananyev        {
243e18a033bSKonstantin Ananyev            ngx_queue_remove(q);
244e18a033bSKonstantin Ananyev            ngx_queue_insert_head(&kp->conf->free, q);
245e18a033bSKonstantin Ananyev
246e18a033bSKonstantin Ananyev            goto found;
247e18a033bSKonstantin Ananyev        }
248e18a033bSKonstantin Ananyev    }
249e18a033bSKonstantin Ananyev
250e18a033bSKonstantin Ananyev    return NGX_OK;
251e18a033bSKonstantin Ananyev
252e18a033bSKonstantin Ananyevfound:
253e18a033bSKonstantin Ananyev
254e18a033bSKonstantin Ananyev    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
255e18a033bSKonstantin Ananyev                   "get keepalive peer: using connection %p", c);
256e18a033bSKonstantin Ananyev
257e18a033bSKonstantin Ananyev    c->idle = 0;
258e18a033bSKonstantin Ananyev    c->sent = 0;
259e18a033bSKonstantin Ananyev    c->log = pc->log;
260e18a033bSKonstantin Ananyev    c->read->log = pc->log;
261e18a033bSKonstantin Ananyev    c->write->log = pc->log;
262e18a033bSKonstantin Ananyev    c->pool->log = pc->log;
263e18a033bSKonstantin Ananyev
264e18a033bSKonstantin Ananyev    pc->connection = c;
265e18a033bSKonstantin Ananyev    pc->cached = 1;
266e18a033bSKonstantin Ananyev
267e18a033bSKonstantin Ananyev    return NGX_DONE;
268e18a033bSKonstantin Ananyev}
269e18a033bSKonstantin Ananyev
270e18a033bSKonstantin Ananyev
271e18a033bSKonstantin Ananyevstatic void
272e18a033bSKonstantin Ananyevngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, void *data,
273e18a033bSKonstantin Ananyev    ngx_uint_t state)
274e18a033bSKonstantin Ananyev{
275e18a033bSKonstantin Ananyev    ngx_http_upstream_keepalive_peer_data_t  *kp = data;
276e18a033bSKonstantin Ananyev    ngx_http_upstream_keepalive_cache_t      *item;
277e18a033bSKonstantin Ananyev
278e18a033bSKonstantin Ananyev    ngx_queue_t          *q;
279e18a033bSKonstantin Ananyev    ngx_connection_t     *c;
280e18a033bSKonstantin Ananyev    ngx_http_upstream_t  *u;
281e18a033bSKonstantin Ananyev
282e18a033bSKonstantin Ananyev    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
283e18a033bSKonstantin Ananyev                   "free keepalive peer");
284e18a033bSKonstantin Ananyev
285e18a033bSKonstantin Ananyev    /* cache valid connections */
286e18a033bSKonstantin Ananyev
287e18a033bSKonstantin Ananyev    u = kp->upstream;
288e18a033bSKonstantin Ananyev    c = pc->connection;
289e18a033bSKonstantin Ananyev
290e18a033bSKonstantin Ananyev    if (state & NGX_PEER_FAILED
291e18a033bSKonstantin Ananyev        || c == NULL
292e18a033bSKonstantin Ananyev        || c->read->eof
293e18a033bSKonstantin Ananyev        || c->read->error
294e18a033bSKonstantin Ananyev        || c->read->timedout
295e18a033bSKonstantin Ananyev        || c->write->error
296e18a033bSKonstantin Ananyev        || c->write->timedout)
297e18a033bSKonstantin Ananyev    {
298e18a033bSKonstantin Ananyev        goto invalid;
299e18a033bSKonstantin Ananyev    }
300e18a033bSKonstantin Ananyev
301e18a033bSKonstantin Ananyev    if (!u->keepalive) {
302e18a033bSKonstantin Ananyev        goto invalid;
303e18a033bSKonstantin Ananyev    }
304e18a033bSKonstantin Ananyev
305e18a033bSKonstantin Ananyev    if (!u->request_body_sent) {
306e18a033bSKonstantin Ananyev        goto invalid;
307e18a033bSKonstantin Ananyev    }
308e18a033bSKonstantin Ananyev
309e18a033bSKonstantin Ananyev    if (ngx_terminate || ngx_exiting) {
310e18a033bSKonstantin Ananyev        goto invalid;
311e18a033bSKonstantin Ananyev    }
312e18a033bSKonstantin Ananyev
313e18a033bSKonstantin Ananyev    if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
314e18a033bSKonstantin Ananyev        goto invalid;
315e18a033bSKonstantin Ananyev    }
316e18a033bSKonstantin Ananyev
317e18a033bSKonstantin Ananyev    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
318e18a033bSKonstantin Ananyev                   "free keepalive peer: saving connection %p", c);
319e18a033bSKonstantin Ananyev
320e18a033bSKonstantin Ananyev    if (ngx_queue_empty(&kp->conf->free)) {
321e18a033bSKonstantin Ananyev
322e18a033bSKonstantin Ananyev        q = ngx_queue_last(&kp->conf->cache);
323e18a033bSKonstantin Ananyev        ngx_queue_remove(q);
324e18a033bSKonstantin Ananyev
325e18a033bSKonstantin Ananyev        item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue);
326e18a033bSKonstantin Ananyev
327e18a033bSKonstantin Ananyev        ngx_http_upstream_keepalive_close(item->connection);
328e18a033bSKonstantin Ananyev
329e18a033bSKonstantin Ananyev    } else {
330e18a033bSKonstantin Ananyev        q = ngx_queue_head(&kp->conf->free);
331e18a033bSKonstantin Ananyev        ngx_queue_remove(q);
332e18a033bSKonstantin Ananyev
333e18a033bSKonstantin Ananyev        item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue);
334e18a033bSKonstantin Ananyev    }
335e18a033bSKonstantin Ananyev
336e18a033bSKonstantin Ananyev    ngx_queue_insert_head(&kp->conf->cache, q);
337e18a033bSKonstantin Ananyev
338e18a033bSKonstantin Ananyev    item->connection = c;
339e18a033bSKonstantin Ananyev
340e18a033bSKonstantin Ananyev    pc->connection = NULL;
341e18a033bSKonstantin Ananyev
342e18a033bSKonstantin Ananyev    if (c->read->timer_set) {
343e18a033bSKonstantin Ananyev        ngx_del_timer(c->read);
344e18a033bSKonstantin Ananyev    }
345e18a033bSKonstantin Ananyev    if (c->write->timer_set) {
346e18a033bSKonstantin Ananyev        ngx_del_timer(c->write);
347e18a033bSKonstantin Ananyev    }
348e18a033bSKonstantin Ananyev
349e18a033bSKonstantin Ananyev    c->write->handler = ngx_http_upstream_keepalive_dummy_handler;
350e18a033bSKonstantin Ananyev    c->read->handler = ngx_http_upstream_keepalive_close_handler;
351e18a033bSKonstantin Ananyev
352e18a033bSKonstantin Ananyev    c->data = item;
353e18a033bSKonstantin Ananyev    c->idle = 1;
354e18a033bSKonstantin Ananyev    c->log = ngx_cycle->log;
355e18a033bSKonstantin Ananyev    c->read->log = ngx_cycle->log;
356e18a033bSKonstantin Ananyev    c->write->log = ngx_cycle->log;
357e18a033bSKonstantin Ananyev    c->pool->log = ngx_cycle->log;
358e18a033bSKonstantin Ananyev
359e18a033bSKonstantin Ananyev    item->socklen = pc->socklen;
360e18a033bSKonstantin Ananyev    ngx_memcpy(&item->sockaddr, pc->sockaddr, pc->socklen);
361e18a033bSKonstantin Ananyev
362e18a033bSKonstantin Ananyev    if (c->read->ready) {
363e18a033bSKonstantin Ananyev        ngx_http_upstream_keepalive_close_handler(c->read);
364e18a033bSKonstantin Ananyev    }
365e18a033bSKonstantin Ananyev
366e18a033bSKonstantin Ananyevinvalid:
367e18a033bSKonstantin Ananyev
368e18a033bSKonstantin Ananyev    kp->original_free_peer(pc, kp->data, state);
369e18a033bSKonstantin Ananyev}
370e18a033bSKonstantin Ananyev
371e18a033bSKonstantin Ananyev
372e18a033bSKonstantin Ananyevstatic void
373e18a033bSKonstantin Ananyevngx_http_upstream_keepalive_dummy_handler(ngx_event_t *ev)
374e18a033bSKonstantin Ananyev{
375e18a033bSKonstantin Ananyev    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
376e18a033bSKonstantin Ananyev                   "keepalive dummy handler");
377e18a033bSKonstantin Ananyev}
378e18a033bSKonstantin Ananyev
379e18a033bSKonstantin Ananyev
380e18a033bSKonstantin Ananyevstatic void
381e18a033bSKonstantin Ananyevngx_http_upstream_keepalive_close_handler(ngx_event_t *ev)
382e18a033bSKonstantin Ananyev{
383e18a033bSKonstantin Ananyev    ngx_http_upstream_keepalive_srv_conf_t  *conf;
384e18a033bSKonstantin Ananyev    ngx_http_upstream_keepalive_cache_t     *item;
385e18a033bSKonstantin Ananyev
386e18a033bSKonstantin Ananyev    int                n;
387e18a033bSKonstantin Ananyev    char               buf[1];
388e18a033bSKonstantin Ananyev    ngx_connection_t  *c;
389e18a033bSKonstantin Ananyev
390e18a033bSKonstantin Ananyev    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
391e18a033bSKonstantin Ananyev                   "keepalive close handler");
392e18a033bSKonstantin Ananyev
393e18a033bSKonstantin Ananyev    c = ev->data;
394e18a033bSKonstantin Ananyev
395e18a033bSKonstantin Ananyev    if (c->close) {
396e18a033bSKonstantin Ananyev        goto close;
397e18a033bSKonstantin Ananyev    }
398e18a033bSKonstantin Ananyev
399e18a033bSKonstantin Ananyev    n = recv(c->fd, buf, 1, MSG_PEEK);
400e18a033bSKonstantin Ananyev
401e18a033bSKonstantin Ananyev    if (n == -1 && ngx_socket_errno == NGX_EAGAIN) {
402e18a033bSKonstantin Ananyev        ev->ready = 0;
403e18a033bSKonstantin Ananyev
404e18a033bSKonstantin Ananyev        if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
405e18a033bSKonstantin Ananyev            goto close;
406e18a033bSKonstantin Ananyev        }
407e18a033bSKonstantin Ananyev
408e18a033bSKonstantin Ananyev        return;
409e18a033bSKonstantin Ananyev    }
410e18a033bSKonstantin Ananyev
411e18a033bSKonstantin Ananyevclose:
412e18a033bSKonstantin Ananyev
413e18a033bSKonstantin Ananyev    item = c->data;
414e18a033bSKonstantin Ananyev    conf = item->conf;
415