blob: 978f39b42a522b83b6a9cf227e3e88f87de925d8 [file] [log] [blame]
Igor Sysoev6b863e32003-05-12 15:52:24 +00001
Igor Sysoevd90282d2004-09-28 08:34:51 +00002/*
Igor Sysoevff8da912004-09-29 16:00:49 +00003 * Copyright (C) Igor Sysoev
Maxim Konovalovf8d59e32012-01-18 15:07:43 +00004 * Copyright (C) Nginx, Inc.
Igor Sysoevd90282d2004-09-28 08:34:51 +00005 */
6
7
Igor Sysoev87a01ea2003-10-02 05:39:37 +00008#include <ngx_config.h>
9#include <ngx_core.h>
10#include <ngx_event.h>
Igor Sysoev6b863e32003-05-12 15:52:24 +000011#include <ngx_event_connect.h>
12
Igor Sysoevae5c59c2003-08-14 06:00:28 +000013
Igor Sysoevaa828612005-02-09 14:31:07 +000014ngx_int_t
15ngx_event_connect_peer(ngx_peer_connection_t *pc)
Igor Sysoev6b863e32003-05-12 15:52:24 +000016{
Igor Sysoev31eb8c02005-09-23 11:02:22 +000017 int rc;
Igor Sysoev708fe2e2007-09-10 09:08:12 +000018 ngx_int_t event;
Igor Sysoev31eb8c02005-09-23 11:02:22 +000019 ngx_err_t err;
Igor Sysoev3d2fd182006-12-04 16:46:13 +000020 ngx_uint_t level;
Igor Sysoev31eb8c02005-09-23 11:02:22 +000021 ngx_socket_t s;
22 ngx_event_t *rev, *wev;
23 ngx_connection_t *c;
Igor Sysoev3a081182003-07-23 13:10:12 +000024
Igor Sysoev3d2fd182006-12-04 16:46:13 +000025 rc = pc->get(pc, pc->data);
26 if (rc != NGX_OK) {
27 return rc;
Igor Sysoev72f2e362003-07-22 19:53:10 +000028 }
29
Igor Sysoev3d2fd182006-12-04 16:46:13 +000030 s = ngx_socket(pc->sockaddr->sa_family, SOCK_STREAM, 0);
Igor Sysoev890fc962003-07-20 21:15:59 +000031
Igor Sysoev3d2fd182006-12-04 16:46:13 +000032 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0, "socket %d", s);
Igor Sysoev899b44e2005-05-12 14:58:06 +000033
Igor Sysoev6b863e32003-05-12 15:52:24 +000034 if (s == -1) {
Igor Sysoev72f2e362003-07-22 19:53:10 +000035 ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
Igor Sysoev6b863e32003-05-12 15:52:24 +000036 ngx_socket_n " failed");
Igor Sysoev890fc962003-07-20 21:15:59 +000037 return NGX_ERROR;
Igor Sysoev6b863e32003-05-12 15:52:24 +000038 }
39
Igor Sysoev732a2712004-04-21 18:54:33 +000040
Igor Sysoev31eb8c02005-09-23 11:02:22 +000041 c = ngx_get_connection(s, pc->log);
Igor Sysoev732a2712004-04-21 18:54:33 +000042
Igor Sysoev31eb8c02005-09-23 11:02:22 +000043 if (c == NULL) {
Igor Sysoev732a2712004-04-21 18:54:33 +000044 if (ngx_close_socket(s) == -1) {
45 ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
46 ngx_close_socket_n "failed");
47 }
48
Igor Sysoev732a2712004-04-21 18:54:33 +000049 return NGX_ERROR;
50 }
51
Igor Sysoev72f2e362003-07-22 19:53:10 +000052 if (pc->rcvbuf) {
Igor Sysoev6b863e32003-05-12 15:52:24 +000053 if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
Igor Sysoevc2068d02005-10-19 12:33:58 +000054 (const void *) &pc->rcvbuf, sizeof(int)) == -1)
55 {
Igor Sysoev72f2e362003-07-22 19:53:10 +000056 ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
Igor Sysoev6b863e32003-05-12 15:52:24 +000057 "setsockopt(SO_RCVBUF) failed");
Igor Sysoev72e92872009-11-02 15:24:02 +000058 goto failed;
Igor Sysoev6b863e32003-05-12 15:52:24 +000059 }
60 }
61
62 if (ngx_nonblocking(s) == -1) {
Igor Sysoev72f2e362003-07-22 19:53:10 +000063 ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
Igor Sysoev6b863e32003-05-12 15:52:24 +000064 ngx_nonblocking_n " failed");
65
Igor Sysoev72e92872009-11-02 15:24:02 +000066 goto failed;
67 }
Igor Sysoev31eb8c02005-09-23 11:02:22 +000068
Igor Sysoev72e92872009-11-02 15:24:02 +000069 if (pc->local) {
70 if (bind(s, pc->local->sockaddr, pc->local->socklen) == -1) {
71 ngx_log_error(NGX_LOG_CRIT, pc->log, ngx_socket_errno,
72 "bind(%V) failed", &pc->local->name);
73
74 goto failed;
Igor Sysoev6b863e32003-05-12 15:52:24 +000075 }
Igor Sysoev6b863e32003-05-12 15:52:24 +000076 }
77
Igor Sysoev31eb8c02005-09-23 11:02:22 +000078 c->recv = ngx_recv;
79 c->send = ngx_send;
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +000080 c->recv_chain = ngx_recv_chain;
Igor Sysoev31eb8c02005-09-23 11:02:22 +000081 c->send_chain = ngx_send_chain;
Igor Sysoeve5a222c2005-01-25 12:27:35 +000082
Igor Sysoeve1013382007-08-14 20:44:09 +000083 c->sendfile = 1;
84
Igor Sysoev31eb8c02005-09-23 11:02:22 +000085 c->log_error = pc->log_error;
Igor Sysoev890fc962003-07-20 21:15:59 +000086
Igor Sysoev3d2fd182006-12-04 16:46:13 +000087 if (pc->sockaddr->sa_family != AF_INET) {
Igor Sysoev31eb8c02005-09-23 11:02:22 +000088 c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED;
89 c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;
Igor Sysoevd3283ff2005-12-05 13:18:09 +000090
91#if (NGX_SOLARIS)
92 /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */
93 c->sendfile = 0;
94#endif
Igor Sysoev72f2e362003-07-22 19:53:10 +000095 }
Igor Sysoev890fc962003-07-20 21:15:59 +000096
Igor Sysoev78452232005-10-12 13:50:36 +000097 rev = c->read;
98 wev = c->write;
Igor Sysoev6b863e32003-05-12 15:52:24 +000099
Igor Sysoev160d7742003-11-19 16:26:41 +0000100 rev->log = pc->log;
101 wev->log = pc->log;
102
Igor Sysoev72f2e362003-07-22 19:53:10 +0000103 pc->connection = c;
104
Igor Sysoev78452232005-10-12 13:50:36 +0000105 c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
Igor Sysoev54498db2004-02-11 17:08:49 +0000106
Igor Sysoevf1be53b2004-07-05 15:08:23 +0000107#if (NGX_THREADS)
Igor Sysoevd5624682009-11-25 18:03:59 +0000108
109 /* TODO: lock event when call completion handler */
110
Igor Sysoevf1be53b2004-07-05 15:08:23 +0000111 rev->lock = pc->lock;
112 wev->lock = pc->lock;
Igor Sysoevc78c41c2004-07-07 06:15:04 +0000113 rev->own_lock = &c->lock;
114 wev->own_lock = &c->lock;
Igor Sysoevd5624682009-11-25 18:03:59 +0000115
Igor Sysoevf1be53b2004-07-05 15:08:23 +0000116#endif
117
Igor Sysoev72f2e362003-07-22 19:53:10 +0000118 if (ngx_add_conn) {
119 if (ngx_add_conn(c) == NGX_ERROR) {
Igor Sysoev72e92872009-11-02 15:24:02 +0000120 goto failed;
Igor Sysoev72f2e362003-07-22 19:53:10 +0000121 }
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000122 }
Igor Sysoev72f2e362003-07-22 19:53:10 +0000123
Igor Sysoev31eb8c02005-09-23 11:02:22 +0000124 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0,
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000125 "connect to %V, fd:%d #%d", pc->name, s, c->number);
Igor Sysoev425a42c2003-10-27 16:16:17 +0000126
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000127 rc = connect(s, pc->sockaddr, pc->socklen);
Igor Sysoev3a081182003-07-23 13:10:12 +0000128
129 if (rc == -1) {
130 err = ngx_socket_errno;
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000131
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000132
Igor Sysoev58e9f222008-07-09 15:42:13 +0000133 if (err != NGX_EINPROGRESS
134#if (NGX_WIN32)
135 /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */
136 && err != NGX_EAGAIN
137#endif
138 )
139 {
Igor Sysoev02d8e8e2008-01-25 14:57:35 +0000140 if (err == NGX_ECONNREFUSED
Igor Sysoev58e9f222008-07-09 15:42:13 +0000141#if (NGX_LINUX)
142 /*
143 * Linux returns EAGAIN instead of ECONNREFUSED
144 * for unix sockets if listen queue is full
145 */
146 || err == NGX_EAGAIN
147#endif
Igor Sysoev288e5032009-02-25 14:27:34 +0000148 || err == NGX_ECONNRESET
Igor Sysoev02d8e8e2008-01-25 14:57:35 +0000149 || err == NGX_ENETDOWN
150 || err == NGX_ENETUNREACH
151 || err == NGX_EHOSTDOWN
152 || err == NGX_EHOSTUNREACH)
153 {
Igor Sysoeve5733802005-09-08 14:36:09 +0000154 level = NGX_LOG_ERR;
Igor Sysoev02d8e8e2008-01-25 14:57:35 +0000155
Igor Sysoeve5733802005-09-08 14:36:09 +0000156 } else {
157 level = NGX_LOG_CRIT;
Igor Sysoevaa828612005-02-09 14:31:07 +0000158 }
Igor Sysoeve5733802005-09-08 14:36:09 +0000159
160 ngx_log_error(level, c->log, err, "connect() to %V failed",
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000161 pc->name);
Igor Sysoev931a4002003-10-07 15:30:05 +0000162
Maxim Dounin4a23bc52012-01-30 11:12:52 +0000163 ngx_close_connection(c);
164 pc->connection = NULL;
165
Igor Sysoev31eb8c02005-09-23 11:02:22 +0000166 return NGX_DECLINED;
Igor Sysoev3a081182003-07-23 13:10:12 +0000167 }
168 }
169
Igor Sysoev67f450d2004-06-01 06:04:46 +0000170 if (ngx_add_conn) {
171 if (rc == -1) {
Igor Sysoevaa828612005-02-09 14:31:07 +0000172
Igor Sysoev67f450d2004-06-01 06:04:46 +0000173 /* NGX_EINPROGRESS */
Igor Sysoevaa828612005-02-09 14:31:07 +0000174
Igor Sysoev67f450d2004-06-01 06:04:46 +0000175 return NGX_AGAIN;
176 }
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000177
Igor Sysoev67f450d2004-06-01 06:04:46 +0000178 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected");
Igor Sysoeve5a222c2005-01-25 12:27:35 +0000179
180 wev->ready = 1;
181
Igor Sysoev67f450d2004-06-01 06:04:46 +0000182 return NGX_OK;
183 }
184
Igor Sysoevb5faed22003-10-29 08:30:44 +0000185 if (ngx_event_flags & NGX_USE_AIO_EVENT) {
Igor Sysoevb5faed22003-10-29 08:30:44 +0000186
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000187 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, ngx_socket_errno,
188 "connect(): %d", rc);
189
Igor Sysoevb5910d42003-10-30 16:51:33 +0000190 /* aio, iocp */
191
192 if (ngx_blocking(s) == -1) {
193 ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
194 ngx_blocking_n " failed");
Igor Sysoev72e92872009-11-02 15:24:02 +0000195 goto failed;
Igor Sysoevb5910d42003-10-30 16:51:33 +0000196 }
197
198 /*
Igor Sysoevaa828612005-02-09 14:31:07 +0000199 * FreeBSD's aio allows to post an operation on non-connected socket.
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000200 * NT does not support it.
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000201 *
Igor Sysoevfe0f5cc2003-10-31 16:05:33 +0000202 * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT
Igor Sysoevb5910d42003-10-30 16:51:33 +0000203 */
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000204
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000205 rev->ready = 1;
Igor Sysoevb5faed22003-10-29 08:30:44 +0000206 wev->ready = 1;
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000207
Igor Sysoevb5faed22003-10-29 08:30:44 +0000208 return NGX_OK;
Igor Sysoevb5faed22003-10-29 08:30:44 +0000209 }
210
Igor Sysoevaa828612005-02-09 14:31:07 +0000211 if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
212
213 /* kqueue */
214
Igor Sysoeve6779222003-10-03 15:50:53 +0000215 event = NGX_CLEAR_EVENT;
216
Igor Sysoevaa828612005-02-09 14:31:07 +0000217 } else {
218
219 /* select, poll, /dev/poll */
220
Igor Sysoeve6779222003-10-03 15:50:53 +0000221 event = NGX_LEVEL_EVENT;
222 }
223
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000224 if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
Igor Sysoev72e92872009-11-02 15:24:02 +0000225 goto failed;
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000226 }
227
Igor Sysoeve6779222003-10-03 15:50:53 +0000228 if (rc == -1) {
229
230 /* NGX_EINPROGRESS */
231
232 if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) {
Igor Sysoev72e92872009-11-02 15:24:02 +0000233 goto failed;
Igor Sysoeve6779222003-10-03 15:50:53 +0000234 }
235
236 return NGX_AGAIN;
237 }
238
Igor Sysoev54498db2004-02-11 17:08:49 +0000239 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected");
Igor Sysoev222a2ad2003-11-18 16:49:00 +0000240
Igor Sysoevd404c972003-10-16 20:19:16 +0000241 wev->ready = 1;
242
Igor Sysoev87a01ea2003-10-02 05:39:37 +0000243 return NGX_OK;
Igor Sysoev72e92872009-11-02 15:24:02 +0000244
245failed:
246
Maxim Dounin4a23bc52012-01-30 11:12:52 +0000247 ngx_close_connection(c);
248 pc->connection = NULL;
Igor Sysoev72e92872009-11-02 15:24:02 +0000249
250 return NGX_ERROR;
Igor Sysoev890fc962003-07-20 21:15:59 +0000251}
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000252
253
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000254ngx_int_t
255ngx_event_get_peer(ngx_peer_connection_t *pc, void *data)
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000256{
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000257 return NGX_OK;
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000258}