xref: /unit/src/nxt_conn_connect.c (revision 1449:8bcb79f5d69d)
162Sigor@sysoev.ru 
262Sigor@sysoev.ru /*
362Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
462Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
562Sigor@sysoev.ru  */
662Sigor@sysoev.ru 
762Sigor@sysoev.ru #include <nxt_main.h>
862Sigor@sysoev.ru 
962Sigor@sysoev.ru 
101263Sigor@sysoev.ru static nxt_err_t nxt_conn_connect_test_error(nxt_task_t *task, nxt_conn_t *c);
111263Sigor@sysoev.ru 
121263Sigor@sysoev.ru 
1362Sigor@sysoev.ru void
nxt_conn_sys_socket(nxt_task_t * task,void * obj,void * data)1462Sigor@sysoev.ru nxt_conn_sys_socket(nxt_task_t *task, void *obj, void *data)
1562Sigor@sysoev.ru {
1662Sigor@sysoev.ru     nxt_conn_t          *c;
1762Sigor@sysoev.ru     nxt_work_handler_t  handler;
1862Sigor@sysoev.ru 
1962Sigor@sysoev.ru     c = obj;
2062Sigor@sysoev.ru 
2162Sigor@sysoev.ru     if (nxt_conn_socket(task, c) == NXT_OK) {
2262Sigor@sysoev.ru         c->socket.write_work_queue = c->write_work_queue;
2362Sigor@sysoev.ru         handler = c->io->connect;
2462Sigor@sysoev.ru 
2562Sigor@sysoev.ru     } else {
2662Sigor@sysoev.ru         handler = c->write_state->error_handler;
2762Sigor@sysoev.ru     }
2862Sigor@sysoev.ru 
2962Sigor@sysoev.ru     nxt_work_queue_add(&task->thread->engine->connect_work_queue,
3062Sigor@sysoev.ru                        handler, task, c, data);
3162Sigor@sysoev.ru }
3262Sigor@sysoev.ru 
3362Sigor@sysoev.ru 
3462Sigor@sysoev.ru void
nxt_conn_io_connect(nxt_task_t * task,void * obj,void * data)3562Sigor@sysoev.ru nxt_conn_io_connect(nxt_task_t *task, void *obj, void *data)
3662Sigor@sysoev.ru {
3762Sigor@sysoev.ru     nxt_conn_t              *c;
3862Sigor@sysoev.ru     nxt_work_handler_t      handler;
3962Sigor@sysoev.ru     nxt_event_engine_t      *engine;
4062Sigor@sysoev.ru     const nxt_conn_state_t  *state;
4162Sigor@sysoev.ru 
4262Sigor@sysoev.ru     c = obj;
4362Sigor@sysoev.ru 
4462Sigor@sysoev.ru     state = c->write_state;
4562Sigor@sysoev.ru 
4662Sigor@sysoev.ru     switch (nxt_socket_connect(task, c->socket.fd, c->remote)) {
4762Sigor@sysoev.ru 
4862Sigor@sysoev.ru     case NXT_OK:
4962Sigor@sysoev.ru         c->socket.write_ready = 1;
5062Sigor@sysoev.ru         handler = state->ready_handler;
5162Sigor@sysoev.ru         break;
5262Sigor@sysoev.ru 
5362Sigor@sysoev.ru     case NXT_AGAIN:
5462Sigor@sysoev.ru         c->socket.write_handler = nxt_conn_connect_test;
551263Sigor@sysoev.ru         c->socket.error_handler = nxt_conn_connect_error;
5662Sigor@sysoev.ru 
5762Sigor@sysoev.ru         engine = task->thread->engine;
5862Sigor@sysoev.ru 
5962Sigor@sysoev.ru         nxt_conn_timer(engine, c, state, &c->write_timer);
6062Sigor@sysoev.ru 
6162Sigor@sysoev.ru         nxt_fd_event_enable_write(engine, &c->socket);
6262Sigor@sysoev.ru         return;
6362Sigor@sysoev.ru 
6462Sigor@sysoev.ru     case NXT_DECLINED:
6562Sigor@sysoev.ru         handler = state->close_handler;
6662Sigor@sysoev.ru         break;
6762Sigor@sysoev.ru 
6862Sigor@sysoev.ru     default: /* NXT_ERROR */
6962Sigor@sysoev.ru         handler = state->error_handler;
7062Sigor@sysoev.ru         break;
7162Sigor@sysoev.ru     }
7262Sigor@sysoev.ru 
7362Sigor@sysoev.ru     nxt_work_queue_add(c->write_work_queue, handler, task, c, data);
7462Sigor@sysoev.ru }
7562Sigor@sysoev.ru 
7662Sigor@sysoev.ru 
7762Sigor@sysoev.ru nxt_int_t
nxt_conn_socket(nxt_task_t * task,nxt_conn_t * c)7862Sigor@sysoev.ru nxt_conn_socket(nxt_task_t *task, nxt_conn_t *c)
7962Sigor@sysoev.ru {
8062Sigor@sysoev.ru     nxt_uint_t    family;
8162Sigor@sysoev.ru     nxt_socket_t  s;
8262Sigor@sysoev.ru 
8362Sigor@sysoev.ru     nxt_debug(task, "event conn socket");
8462Sigor@sysoev.ru 
8562Sigor@sysoev.ru     family = c->remote->u.sockaddr.sa_family;
8662Sigor@sysoev.ru 
8762Sigor@sysoev.ru     s = nxt_socket_create(task, family, c->remote->type, 0, NXT_NONBLOCK);
8862Sigor@sysoev.ru 
8962Sigor@sysoev.ru     if (nxt_slow_path(s == -1)) {
9062Sigor@sysoev.ru         return NXT_ERROR;
9162Sigor@sysoev.ru     }
9262Sigor@sysoev.ru 
9362Sigor@sysoev.ru     c->sendfile = 1;
9462Sigor@sysoev.ru 
9562Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN && NXT_SOLARIS)
9662Sigor@sysoev.ru 
9762Sigor@sysoev.ru     if (family == AF_UNIX) {
9862Sigor@sysoev.ru         /* Solaris AF_UNIX does not support sendfilev(). */
9962Sigor@sysoev.ru         c->sendfile = 0;
10062Sigor@sysoev.ru     }
10162Sigor@sysoev.ru 
10262Sigor@sysoev.ru #endif
10362Sigor@sysoev.ru 
10462Sigor@sysoev.ru     c->socket.fd = s;
10562Sigor@sysoev.ru 
10662Sigor@sysoev.ru     c->socket.task = task;
10762Sigor@sysoev.ru     c->read_timer.task = task;
10862Sigor@sysoev.ru     c->write_timer.task = task;
10962Sigor@sysoev.ru 
11062Sigor@sysoev.ru     if (c->local != NULL) {
111*1449Svbart@nginx.com         if (nxt_slow_path(nxt_socket_bind(task, s, c->local) != NXT_OK)) {
11262Sigor@sysoev.ru             nxt_socket_close(task, s);
11362Sigor@sysoev.ru             return NXT_ERROR;
11462Sigor@sysoev.ru         }
11562Sigor@sysoev.ru     }
11662Sigor@sysoev.ru 
11762Sigor@sysoev.ru     return NXT_OK;
11862Sigor@sysoev.ru }
11962Sigor@sysoev.ru 
12062Sigor@sysoev.ru 
12162Sigor@sysoev.ru void
nxt_conn_connect_test(nxt_task_t * task,void * obj,void * data)12262Sigor@sysoev.ru nxt_conn_connect_test(nxt_task_t *task, void *obj, void *data)
12362Sigor@sysoev.ru {
1241263Sigor@sysoev.ru     nxt_err_t   err;
12562Sigor@sysoev.ru     nxt_conn_t  *c;
12662Sigor@sysoev.ru 
12762Sigor@sysoev.ru     c = obj;
12862Sigor@sysoev.ru 
12962Sigor@sysoev.ru     nxt_debug(task, "event connect test fd:%d", c->socket.fd);
13062Sigor@sysoev.ru 
13162Sigor@sysoev.ru     nxt_fd_event_block_write(task->thread->engine, &c->socket);
13262Sigor@sysoev.ru 
13362Sigor@sysoev.ru     if (c->write_state->timer_autoreset) {
13462Sigor@sysoev.ru         nxt_timer_disable(task->thread->engine, &c->write_timer);
13562Sigor@sysoev.ru     }
13662Sigor@sysoev.ru 
1371263Sigor@sysoev.ru     err = nxt_conn_connect_test_error(task, c);
13862Sigor@sysoev.ru 
13962Sigor@sysoev.ru     if (err == 0) {
14062Sigor@sysoev.ru         nxt_work_queue_add(c->write_work_queue, c->write_state->ready_handler,
14162Sigor@sysoev.ru                            task, c, data);
1421263Sigor@sysoev.ru     } else {
1431263Sigor@sysoev.ru         nxt_conn_connect_error(task, c, data);
14462Sigor@sysoev.ru     }
14562Sigor@sysoev.ru }
14662Sigor@sysoev.ru 
14762Sigor@sysoev.ru 
14862Sigor@sysoev.ru void
nxt_conn_connect_error(nxt_task_t * task,void * obj,void * data)14962Sigor@sysoev.ru nxt_conn_connect_error(nxt_task_t *task, void *obj, void *data)
15062Sigor@sysoev.ru {
1511263Sigor@sysoev.ru     nxt_err_t               err;
15262Sigor@sysoev.ru     nxt_conn_t              *c;
15362Sigor@sysoev.ru     nxt_work_handler_t      handler;
15462Sigor@sysoev.ru     const nxt_conn_state_t  *state;
15562Sigor@sysoev.ru 
15662Sigor@sysoev.ru     c = obj;
1571263Sigor@sysoev.ru     err = c->socket.error;
1581263Sigor@sysoev.ru 
1591263Sigor@sysoev.ru     if (err == 0) {
1601263Sigor@sysoev.ru         err = nxt_conn_connect_test_error(task, c);
1611263Sigor@sysoev.ru     }
16262Sigor@sysoev.ru 
16362Sigor@sysoev.ru     state = c->write_state;
16462Sigor@sysoev.ru 
1651263Sigor@sysoev.ru     switch (err) {
16662Sigor@sysoev.ru 
16762Sigor@sysoev.ru     case NXT_ECONNREFUSED:
16862Sigor@sysoev.ru #if (NXT_LINUX)
16962Sigor@sysoev.ru     case NXT_EAGAIN:
17062Sigor@sysoev.ru         /*
17162Sigor@sysoev.ru          * Linux returns EAGAIN instead of ECONNREFUSED
17262Sigor@sysoev.ru          * for UNIX sockets if a listen queue is full.
17362Sigor@sysoev.ru          */
17462Sigor@sysoev.ru #endif
17562Sigor@sysoev.ru         handler = state->close_handler;
17662Sigor@sysoev.ru         break;
17762Sigor@sysoev.ru 
17862Sigor@sysoev.ru     default:
17962Sigor@sysoev.ru         handler = state->error_handler;
18062Sigor@sysoev.ru         break;
18162Sigor@sysoev.ru     }
18262Sigor@sysoev.ru 
18362Sigor@sysoev.ru     nxt_work_queue_add(c->write_work_queue, handler, task, c, data);
18462Sigor@sysoev.ru }
1851263Sigor@sysoev.ru 
1861263Sigor@sysoev.ru 
1871263Sigor@sysoev.ru static nxt_err_t
nxt_conn_connect_test_error(nxt_task_t * task,nxt_conn_t * c)1881263Sigor@sysoev.ru nxt_conn_connect_test_error(nxt_task_t *task, nxt_conn_t *c)
1891263Sigor@sysoev.ru {
1901263Sigor@sysoev.ru     nxt_err_t  err;
1911263Sigor@sysoev.ru 
1921263Sigor@sysoev.ru     err = nxt_socket_error(c->socket.fd);
1931263Sigor@sysoev.ru 
1941263Sigor@sysoev.ru     if (err != 0) {
1951263Sigor@sysoev.ru         c->socket.error = err;
1961263Sigor@sysoev.ru 
1971263Sigor@sysoev.ru         nxt_log(task, nxt_socket_error_level(err), "connect(%d, %*s) failed %E",
1981263Sigor@sysoev.ru                 c->socket.fd, (size_t) c->remote->length,
1991263Sigor@sysoev.ru                 nxt_sockaddr_start(c->remote), err);
2001263Sigor@sysoev.ru     }
2011263Sigor@sysoev.ru 
2021263Sigor@sysoev.ru     return err;
2031263Sigor@sysoev.ru }
204