xref: /unit/src/nxt_conn_close.c (revision 564:762f8c976ead)
153Sigor@sysoev.ru 
253Sigor@sysoev.ru /*
353Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
453Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
553Sigor@sysoev.ru  */
653Sigor@sysoev.ru 
753Sigor@sysoev.ru #include <nxt_main.h>
853Sigor@sysoev.ru 
953Sigor@sysoev.ru 
1053Sigor@sysoev.ru static void nxt_conn_shutdown_handler(nxt_task_t *task, void *obj, void *data);
1153Sigor@sysoev.ru static void nxt_conn_close_handler(nxt_task_t *task, void *obj, void *data);
1253Sigor@sysoev.ru static void nxt_conn_close_timer_handler(nxt_task_t *task, void *obj,
1353Sigor@sysoev.ru     void *data);
1453Sigor@sysoev.ru static void nxt_conn_close_error_ignore(nxt_task_t *task, void *obj,
1553Sigor@sysoev.ru     void *data);
1653Sigor@sysoev.ru 
1753Sigor@sysoev.ru 
1853Sigor@sysoev.ru void
nxt_conn_close(nxt_event_engine_t * engine,nxt_conn_t * c)1962Sigor@sysoev.ru nxt_conn_close(nxt_event_engine_t *engine, nxt_conn_t *c)
2053Sigor@sysoev.ru {
2153Sigor@sysoev.ru     int                 ret;
2253Sigor@sysoev.ru     nxt_work_queue_t    *wq;
2353Sigor@sysoev.ru     nxt_work_handler_t  handler;
2453Sigor@sysoev.ru 
25109Sigor@sysoev.ru     static const struct linger  linger_off = {
26109Sigor@sysoev.ru         .l_onoff = 1,
27109Sigor@sysoev.ru         .l_linger = 0,
28109Sigor@sysoev.ru     };
29109Sigor@sysoev.ru 
3053Sigor@sysoev.ru     nxt_debug(c->socket.task, "conn close fd:%d, to:%d",
3153Sigor@sysoev.ru               c->socket.fd, c->socket.timedout);
3253Sigor@sysoev.ru 
33419Sigor@sysoev.ru     /*
34419Sigor@sysoev.ru      * Disable all pending write operations because on success they
35419Sigor@sysoev.ru      * will incorrectly call a ready handler set for nxt_conn_close().
36419Sigor@sysoev.ru      */
37419Sigor@sysoev.ru     c->write = NULL;
38419Sigor@sysoev.ru 
3953Sigor@sysoev.ru     if (c->socket.timedout) {
4053Sigor@sysoev.ru         /*
4153Sigor@sysoev.ru          * Resetting of timed out connection on close
4253Sigor@sysoev.ru          * releases kernel memory associated with socket.
4353Sigor@sysoev.ru          * This also causes sending TCP/IP RST to a peer.
4453Sigor@sysoev.ru          */
45109Sigor@sysoev.ru         ret = setsockopt(c->socket.fd, SOL_SOCKET, SO_LINGER, &linger_off,
46109Sigor@sysoev.ru                          sizeof(struct linger));
4753Sigor@sysoev.ru 
4853Sigor@sysoev.ru         if (nxt_slow_path(ret != 0)) {
49*564Svbart@nginx.com             nxt_alert(c->socket.task, "setsockopt(%d, SO_LINGER) failed %E",
50*564Svbart@nginx.com                       c->socket.fd, nxt_socket_errno);
5153Sigor@sysoev.ru         }
5253Sigor@sysoev.ru     }
5353Sigor@sysoev.ru 
5453Sigor@sysoev.ru     /*
5553Sigor@sysoev.ru      * Event errors should be ignored here to avoid repeated nxt_conn_close()
5653Sigor@sysoev.ru      * calls.  nxt_conn_close_handler() or nxt_conn_close_timer_handler()
5753Sigor@sysoev.ru      * will eventually close socket.
5853Sigor@sysoev.ru      */
5953Sigor@sysoev.ru     c->socket.error_handler = nxt_conn_close_error_ignore;
6053Sigor@sysoev.ru 
6153Sigor@sysoev.ru     if (c->socket.error == 0 && !c->socket.closed && !c->socket.shutdown) {
6253Sigor@sysoev.ru         wq = &engine->shutdown_work_queue;
6353Sigor@sysoev.ru         handler = nxt_conn_shutdown_handler;
6453Sigor@sysoev.ru 
65521Szelenkov@nginx.com     } else {
6653Sigor@sysoev.ru         wq = &engine->close_work_queue;
6753Sigor@sysoev.ru         handler = nxt_conn_close_handler;
6853Sigor@sysoev.ru     }
6953Sigor@sysoev.ru 
7053Sigor@sysoev.ru     nxt_work_queue_add(wq, handler, c->socket.task, c, engine);
7153Sigor@sysoev.ru }
7253Sigor@sysoev.ru 
7353Sigor@sysoev.ru 
7453Sigor@sysoev.ru static void
nxt_conn_shutdown_handler(nxt_task_t * task,void * obj,void * data)7553Sigor@sysoev.ru nxt_conn_shutdown_handler(nxt_task_t *task, void *obj, void *data)
7653Sigor@sysoev.ru {
7762Sigor@sysoev.ru     nxt_conn_t          *c;
7853Sigor@sysoev.ru     nxt_event_engine_t  *engine;
7953Sigor@sysoev.ru 
8053Sigor@sysoev.ru     c = obj;
8153Sigor@sysoev.ru     engine = data;
8253Sigor@sysoev.ru 
8353Sigor@sysoev.ru     nxt_debug(task, "conn shutdown handler fd:%d", c->socket.fd);
8453Sigor@sysoev.ru 
8553Sigor@sysoev.ru     c->socket.shutdown = 1;
8653Sigor@sysoev.ru 
8753Sigor@sysoev.ru     nxt_socket_shutdown(task, c->socket.fd, SHUT_RDWR);
8853Sigor@sysoev.ru 
8953Sigor@sysoev.ru     nxt_work_queue_add(&engine->close_work_queue, nxt_conn_close_handler,
9053Sigor@sysoev.ru                        task, c, engine);
9153Sigor@sysoev.ru }
9253Sigor@sysoev.ru 
9353Sigor@sysoev.ru 
9453Sigor@sysoev.ru static void
nxt_conn_close_handler(nxt_task_t * task,void * obj,void * data)9553Sigor@sysoev.ru nxt_conn_close_handler(nxt_task_t *task, void *obj, void *data)
9653Sigor@sysoev.ru {
9753Sigor@sysoev.ru     nxt_uint_t          events_pending, timers_pending;
9862Sigor@sysoev.ru     nxt_conn_t          *c;
9953Sigor@sysoev.ru     nxt_event_engine_t  *engine;
10053Sigor@sysoev.ru 
10153Sigor@sysoev.ru     c = obj;
10253Sigor@sysoev.ru     engine = data;
10353Sigor@sysoev.ru 
10453Sigor@sysoev.ru     nxt_debug(task, "conn close handler fd:%d", c->socket.fd);
10553Sigor@sysoev.ru 
10653Sigor@sysoev.ru     /*
10753Sigor@sysoev.ru      * Socket should be closed only after all pending socket event operations
10853Sigor@sysoev.ru      * will be processed by the kernel.  This could be achieved with zero-timer
10953Sigor@sysoev.ru      * handler.  Pending timer operations associated with the socket are
11053Sigor@sysoev.ru      * processed before going to the kernel.
11153Sigor@sysoev.ru      */
11253Sigor@sysoev.ru 
11353Sigor@sysoev.ru     timers_pending = nxt_timer_delete(engine, &c->read_timer);
11453Sigor@sysoev.ru     timers_pending += nxt_timer_delete(engine, &c->write_timer);
11553Sigor@sysoev.ru 
11653Sigor@sysoev.ru     events_pending = nxt_fd_event_close(engine, &c->socket);
11753Sigor@sysoev.ru 
11853Sigor@sysoev.ru     if (events_pending == 0) {
11953Sigor@sysoev.ru         nxt_socket_close(task, c->socket.fd);
12053Sigor@sysoev.ru         c->socket.fd = -1;
12153Sigor@sysoev.ru 
12253Sigor@sysoev.ru         if (timers_pending == 0) {
12353Sigor@sysoev.ru             nxt_work_queue_add(&engine->fast_work_queue,
12453Sigor@sysoev.ru                                c->write_state->ready_handler,
12553Sigor@sysoev.ru                                task, c, c->socket.data);
12653Sigor@sysoev.ru             return;
12753Sigor@sysoev.ru         }
12853Sigor@sysoev.ru     }
12953Sigor@sysoev.ru 
13053Sigor@sysoev.ru     c->write_timer.handler = nxt_conn_close_timer_handler;
13153Sigor@sysoev.ru     c->write_timer.work_queue = &engine->fast_work_queue;
13253Sigor@sysoev.ru 
13353Sigor@sysoev.ru     nxt_timer_add(engine, &c->write_timer, 0);
13453Sigor@sysoev.ru }
13553Sigor@sysoev.ru 
13653Sigor@sysoev.ru 
13753Sigor@sysoev.ru static void
nxt_conn_close_timer_handler(nxt_task_t * task,void * obj,void * data)13853Sigor@sysoev.ru nxt_conn_close_timer_handler(nxt_task_t *task, void *obj, void *data)
13953Sigor@sysoev.ru {
14062Sigor@sysoev.ru     nxt_conn_t   *c;
14162Sigor@sysoev.ru     nxt_timer_t  *timer;
14253Sigor@sysoev.ru 
14353Sigor@sysoev.ru     timer = obj;
14453Sigor@sysoev.ru 
14562Sigor@sysoev.ru     c = nxt_write_timer_conn(timer);
14653Sigor@sysoev.ru 
14753Sigor@sysoev.ru     nxt_debug(task, "conn close timer handler fd:%d", c->socket.fd);
14853Sigor@sysoev.ru 
14953Sigor@sysoev.ru     if (c->socket.fd != -1) {
15053Sigor@sysoev.ru         nxt_socket_close(task, c->socket.fd);
15153Sigor@sysoev.ru         c->socket.fd = -1;
15253Sigor@sysoev.ru     }
15353Sigor@sysoev.ru 
15453Sigor@sysoev.ru     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
15553Sigor@sysoev.ru                        c->write_state->ready_handler,
15653Sigor@sysoev.ru                        task, c, c->socket.data);
15753Sigor@sysoev.ru }
15853Sigor@sysoev.ru 
15953Sigor@sysoev.ru 
16053Sigor@sysoev.ru static void
nxt_conn_close_error_ignore(nxt_task_t * task,void * obj,void * data)16153Sigor@sysoev.ru nxt_conn_close_error_ignore(nxt_task_t *task, void *obj, void *data)
16253Sigor@sysoev.ru {
16353Sigor@sysoev.ru     nxt_debug(task, "conn close error ignore");
16453Sigor@sysoev.ru }
165