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