1 2/* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7#include <nxt_main.h> 8 9
| 1 2/* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7#include <nxt_main.h> 8 9
|
| 10static nxt_err_t nxt_conn_connect_test_error(nxt_task_t *task, nxt_conn_t *c); 11 12
|
10void 11nxt_conn_sys_socket(nxt_task_t *task, void *obj, void *data) 12{ 13 nxt_conn_t *c; 14 nxt_work_handler_t handler; 15 16 c = obj; 17 18 if (nxt_conn_socket(task, c) == NXT_OK) { 19 c->socket.write_work_queue = c->write_work_queue; 20 handler = c->io->connect; 21 22 } else { 23 handler = c->write_state->error_handler; 24 } 25 26 nxt_work_queue_add(&task->thread->engine->connect_work_queue, 27 handler, task, c, data); 28} 29 30 31void 32nxt_conn_io_connect(nxt_task_t *task, void *obj, void *data) 33{ 34 nxt_conn_t *c; 35 nxt_work_handler_t handler; 36 nxt_event_engine_t *engine; 37 const nxt_conn_state_t *state; 38 39 c = obj; 40 41 state = c->write_state; 42 43 switch (nxt_socket_connect(task, c->socket.fd, c->remote)) { 44 45 case NXT_OK: 46 c->socket.write_ready = 1; 47 handler = state->ready_handler; 48 break; 49 50 case NXT_AGAIN: 51 c->socket.write_handler = nxt_conn_connect_test;
| 13void 14nxt_conn_sys_socket(nxt_task_t *task, void *obj, void *data) 15{ 16 nxt_conn_t *c; 17 nxt_work_handler_t handler; 18 19 c = obj; 20 21 if (nxt_conn_socket(task, c) == NXT_OK) { 22 c->socket.write_work_queue = c->write_work_queue; 23 handler = c->io->connect; 24 25 } else { 26 handler = c->write_state->error_handler; 27 } 28 29 nxt_work_queue_add(&task->thread->engine->connect_work_queue, 30 handler, task, c, data); 31} 32 33 34void 35nxt_conn_io_connect(nxt_task_t *task, void *obj, void *data) 36{ 37 nxt_conn_t *c; 38 nxt_work_handler_t handler; 39 nxt_event_engine_t *engine; 40 const nxt_conn_state_t *state; 41 42 c = obj; 43 44 state = c->write_state; 45 46 switch (nxt_socket_connect(task, c->socket.fd, c->remote)) { 47 48 case NXT_OK: 49 c->socket.write_ready = 1; 50 handler = state->ready_handler; 51 break; 52 53 case NXT_AGAIN: 54 c->socket.write_handler = nxt_conn_connect_test;
|
52 c->socket.error_handler = state->error_handler;
| 55 c->socket.error_handler = nxt_conn_connect_error;
|
53 54 engine = task->thread->engine; 55 56 nxt_conn_timer(engine, c, state, &c->write_timer); 57 58 nxt_fd_event_enable_write(engine, &c->socket); 59 return; 60 61 case NXT_DECLINED: 62 handler = state->close_handler; 63 break; 64 65 default: /* NXT_ERROR */ 66 handler = state->error_handler; 67 break; 68 } 69 70 nxt_work_queue_add(c->write_work_queue, handler, task, c, data); 71} 72 73 74nxt_int_t 75nxt_conn_socket(nxt_task_t *task, nxt_conn_t *c) 76{ 77 nxt_uint_t family; 78 nxt_socket_t s; 79 80 nxt_debug(task, "event conn socket"); 81 82 family = c->remote->u.sockaddr.sa_family; 83 84 s = nxt_socket_create(task, family, c->remote->type, 0, NXT_NONBLOCK); 85 86 if (nxt_slow_path(s == -1)) { 87 return NXT_ERROR; 88 } 89 90 c->sendfile = 1; 91 92#if (NXT_HAVE_UNIX_DOMAIN && NXT_SOLARIS) 93 94 if (family == AF_UNIX) { 95 /* Solaris AF_UNIX does not support sendfilev(). */ 96 c->sendfile = 0; 97 } 98 99#endif 100 101 c->socket.fd = s; 102 103 c->socket.task = task; 104 c->read_timer.task = task; 105 c->write_timer.task = task; 106 107 if (c->local != NULL) { 108 if (nxt_slow_path(nxt_socket_bind(task, s, c->local, 0) != NXT_OK)) { 109 nxt_socket_close(task, s); 110 return NXT_ERROR; 111 } 112 } 113 114 return NXT_OK; 115} 116 117 118void 119nxt_conn_connect_test(nxt_task_t *task, void *obj, void *data) 120{
| 56 57 engine = task->thread->engine; 58 59 nxt_conn_timer(engine, c, state, &c->write_timer); 60 61 nxt_fd_event_enable_write(engine, &c->socket); 62 return; 63 64 case NXT_DECLINED: 65 handler = state->close_handler; 66 break; 67 68 default: /* NXT_ERROR */ 69 handler = state->error_handler; 70 break; 71 } 72 73 nxt_work_queue_add(c->write_work_queue, handler, task, c, data); 74} 75 76 77nxt_int_t 78nxt_conn_socket(nxt_task_t *task, nxt_conn_t *c) 79{ 80 nxt_uint_t family; 81 nxt_socket_t s; 82 83 nxt_debug(task, "event conn socket"); 84 85 family = c->remote->u.sockaddr.sa_family; 86 87 s = nxt_socket_create(task, family, c->remote->type, 0, NXT_NONBLOCK); 88 89 if (nxt_slow_path(s == -1)) { 90 return NXT_ERROR; 91 } 92 93 c->sendfile = 1; 94 95#if (NXT_HAVE_UNIX_DOMAIN && NXT_SOLARIS) 96 97 if (family == AF_UNIX) { 98 /* Solaris AF_UNIX does not support sendfilev(). */ 99 c->sendfile = 0; 100 } 101 102#endif 103 104 c->socket.fd = s; 105 106 c->socket.task = task; 107 c->read_timer.task = task; 108 c->write_timer.task = task; 109 110 if (c->local != NULL) { 111 if (nxt_slow_path(nxt_socket_bind(task, s, c->local, 0) != NXT_OK)) { 112 nxt_socket_close(task, s); 113 return NXT_ERROR; 114 } 115 } 116 117 return NXT_OK; 118} 119 120 121void 122nxt_conn_connect_test(nxt_task_t *task, void *obj, void *data) 123{
|
121 int ret, err; 122 socklen_t len;
| 124 nxt_err_t err;
|
123 nxt_conn_t *c; 124 125 c = obj; 126 127 nxt_debug(task, "event connect test fd:%d", c->socket.fd); 128 129 nxt_fd_event_block_write(task->thread->engine, &c->socket); 130 131 if (c->write_state->timer_autoreset) { 132 nxt_timer_disable(task->thread->engine, &c->write_timer); 133 } 134
| 125 nxt_conn_t *c; 126 127 c = obj; 128 129 nxt_debug(task, "event connect test fd:%d", c->socket.fd); 130 131 nxt_fd_event_block_write(task->thread->engine, &c->socket); 132 133 if (c->write_state->timer_autoreset) { 134 nxt_timer_disable(task->thread->engine, &c->write_timer); 135 } 136
|
135 err = 0; 136 len = sizeof(int);
| 137 err = nxt_conn_connect_test_error(task, c);
|
137
| 138
|
138 /* 139 * Linux and BSDs return 0 and store a pending error in the err argument; 140 * Solaris returns -1 and sets the errno. 141 */ 142 143 ret = getsockopt(c->socket.fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len); 144 145 if (nxt_slow_path(ret == -1)) { 146 err = nxt_errno; 147 } 148
| |
149 if (err == 0) { 150 nxt_work_queue_add(c->write_work_queue, c->write_state->ready_handler, 151 task, c, data);
| 139 if (err == 0) { 140 nxt_work_queue_add(c->write_work_queue, c->write_state->ready_handler, 141 task, c, data);
|
152 return;
| 142 } else { 143 nxt_conn_connect_error(task, c, data);
|
153 }
| 144 }
|
154 155 c->socket.error = err; 156 157 nxt_log(task, nxt_socket_error_level(err), "connect(%d, %*s) failed %E", 158 c->socket.fd, (size_t) c->remote->length, 159 nxt_sockaddr_start(c->remote), err); 160 161 nxt_conn_connect_error(task, c, data);
| |
162} 163 164 165void 166nxt_conn_connect_error(nxt_task_t *task, void *obj, void *data) 167{
| 145} 146 147 148void 149nxt_conn_connect_error(nxt_task_t *task, void *obj, void *data) 150{
|
| 151 nxt_err_t err;
|
168 nxt_conn_t *c; 169 nxt_work_handler_t handler; 170 const nxt_conn_state_t *state; 171 172 c = obj;
| 152 nxt_conn_t *c; 153 nxt_work_handler_t handler; 154 const nxt_conn_state_t *state; 155 156 c = obj;
|
| 157 err = c->socket.error;
|
173
| 158
|
| 159 if (err == 0) { 160 err = nxt_conn_connect_test_error(task, c); 161 } 162
|
174 state = c->write_state; 175
| 163 state = c->write_state; 164
|
176 switch (c->socket.error) {
| 165 switch (err) {
|
177 178 case NXT_ECONNREFUSED: 179#if (NXT_LINUX) 180 case NXT_EAGAIN: 181 /* 182 * Linux returns EAGAIN instead of ECONNREFUSED 183 * for UNIX sockets if a listen queue is full. 184 */ 185#endif 186 handler = state->close_handler; 187 break; 188 189 default: 190 handler = state->error_handler; 191 break; 192 } 193 194 nxt_work_queue_add(c->write_work_queue, handler, task, c, data); 195}
| 166 167 case NXT_ECONNREFUSED: 168#if (NXT_LINUX) 169 case NXT_EAGAIN: 170 /* 171 * Linux returns EAGAIN instead of ECONNREFUSED 172 * for UNIX sockets if a listen queue is full. 173 */ 174#endif 175 handler = state->close_handler; 176 break; 177 178 default: 179 handler = state->error_handler; 180 break; 181 } 182 183 nxt_work_queue_add(c->write_work_queue, handler, task, c, data); 184}
|
| 185 186 187static nxt_err_t 188nxt_conn_connect_test_error(nxt_task_t *task, nxt_conn_t *c) 189{ 190 nxt_err_t err; 191 192 err = nxt_socket_error(c->socket.fd); 193 194 if (err != 0) { 195 c->socket.error = err; 196 197 nxt_log(task, nxt_socket_error_level(err), "connect(%d, %*s) failed %E", 198 c->socket.fd, (size_t) c->remote->length, 199 nxt_sockaddr_start(c->remote), err); 200 } 201 202 return err; 203}
|
| |