blob: 7884cd8b69a98dea1ba0f6ca4a802381cd8f807c [file] [log] [blame]
Igor Sysoev6b863e32003-05-12 15:52:24 +00001
Igor Sysoev87a01ea2003-10-02 05:39:37 +00002#include <ngx_config.h>
3#include <ngx_core.h>
4#include <ngx_event.h>
Igor Sysoev6b863e32003-05-12 15:52:24 +00005#include <ngx_event_connect.h>
6
Igor Sysoevae5c59c2003-08-14 06:00:28 +00007
Igor Sysoev3a081182003-07-23 13:10:12 +00008/* AF_INET only */
Igor Sysoev6b863e32003-05-12 15:52:24 +00009
Igor Sysoev04410502003-08-01 14:56:33 +000010int ngx_event_connect_peer(ngx_peer_connection_t *pc)
Igor Sysoev6b863e32003-05-12 15:52:24 +000011{
Igor Sysoevd9d0ca12003-11-21 06:30:49 +000012 int rc, instance;
13 u_int event;
Igor Sysoev3a081182003-07-23 13:10:12 +000014 time_t now;
Igor Sysoev87a01ea2003-10-02 05:39:37 +000015 ngx_err_t err;
16 ngx_peer_t *peer;
Igor Sysoev3a081182003-07-23 13:10:12 +000017 ngx_socket_t s;
Igor Sysoev87a01ea2003-10-02 05:39:37 +000018 ngx_event_t *rev, *wev;
19 ngx_connection_t *c;
20 struct sockaddr_in addr;
Igor Sysoev3a081182003-07-23 13:10:12 +000021
Igor Sysoev3a081182003-07-23 13:10:12 +000022 now = ngx_time();
Igor Sysoev6b863e32003-05-12 15:52:24 +000023
Igor Sysoev72f2e362003-07-22 19:53:10 +000024 /* ngx_lock_mutex(pc->peers->mutex); */
25
26 if (pc->peers->last_cached) {
27
28 /* cached connection */
29
Igor Sysoevae5c59c2003-08-14 06:00:28 +000030 pc->connection = pc->peers->cached[pc->peers->last_cached];
Igor Sysoev72f2e362003-07-22 19:53:10 +000031 pc->peers->last_cached--;
32
33 /* ngx_unlock_mutex(pc->peers->mutex); */
34
35 pc->cached = 1;
36 return NGX_OK;
37 }
38
Igor Sysoev72f2e362003-07-22 19:53:10 +000039 pc->cached = 0;
Igor Sysoev04410502003-08-01 14:56:33 +000040 pc->connection = NULL;
Igor Sysoev890fc962003-07-20 21:15:59 +000041
Igor Sysoev219d44d2003-10-31 07:10:36 +000042 if (pc->peers->number == 1) {
43 peer = &pc->peers->peers[0];
44
45 } else {
Igor Sysoev6b863e32003-05-12 15:52:24 +000046
Igor Sysoev890fc962003-07-20 21:15:59 +000047 /* there are several peers */
Igor Sysoev6b863e32003-05-12 15:52:24 +000048
Igor Sysoev5b8d3882003-07-21 16:24:25 +000049 if (pc->tries == pc->peers->number) {
Igor Sysoev6b863e32003-05-12 15:52:24 +000050
Igor Sysoev890fc962003-07-20 21:15:59 +000051 /* it's a first try - get a current peer */
52
Igor Sysoev5b8d3882003-07-21 16:24:25 +000053 pc->cur_peer = pc->peers->current++;
Igor Sysoev6b863e32003-05-12 15:52:24 +000054
Igor Sysoev87a01ea2003-10-02 05:39:37 +000055 if (pc->peers->current >= pc->peers->number) {
Igor Sysoev5b8d3882003-07-21 16:24:25 +000056 pc->peers->current = 0;
Igor Sysoev6b863e32003-05-12 15:52:24 +000057 }
Igor Sysoev6b863e32003-05-12 15:52:24 +000058 }
59
Igor Sysoev219d44d2003-10-31 07:10:36 +000060 if (pc->peers->max_fails == 0) {
61 peer = &pc->peers->peers[pc->cur_peer];
62
63 } else {
Igor Sysoev6b863e32003-05-12 15:52:24 +000064
Igor Sysoev890fc962003-07-20 21:15:59 +000065 /* the peers support a fault tolerance */
66
Igor Sysoev6b863e32003-05-12 15:52:24 +000067 for ( ;; ) {
Igor Sysoev5b8d3882003-07-21 16:24:25 +000068 peer = &pc->peers->peers[pc->cur_peer];
Igor Sysoev6b863e32003-05-12 15:52:24 +000069
Igor Sysoev5b8d3882003-07-21 16:24:25 +000070 if (peer->fails <= pc->peers->max_fails
71 || (now - peer->accessed > pc->peers->fail_timeout))
Igor Sysoev6b863e32003-05-12 15:52:24 +000072 {
73 break;
74 }
75
Igor Sysoev5b8d3882003-07-21 16:24:25 +000076 pc->cur_peer++;
Igor Sysoev6b863e32003-05-12 15:52:24 +000077
Igor Sysoev5b8d3882003-07-21 16:24:25 +000078 if (pc->cur_peer >= pc->peers->number) {
79 pc->cur_peer = 0;
Igor Sysoev6b863e32003-05-12 15:52:24 +000080 }
81
Igor Sysoev5b8d3882003-07-21 16:24:25 +000082 pc->tries--;
Igor Sysoev6b863e32003-05-12 15:52:24 +000083
Igor Sysoev5b8d3882003-07-21 16:24:25 +000084 if (pc->tries == 0) {
Igor Sysoev3a081182003-07-23 13:10:12 +000085 /* ngx_unlock_mutex(pc->peers->mutex); */
Igor Sysoev87a01ea2003-10-02 05:39:37 +000086
Igor Sysoev6b863e32003-05-12 15:52:24 +000087 return NGX_ERROR;
88 }
89 }
90 }
91 }
92
Igor Sysoev3a081182003-07-23 13:10:12 +000093 /* ngx_unlock_mutex(pc->peers->mutex); */
94
Igor Sysoev6b863e32003-05-12 15:52:24 +000095
96 s = ngx_socket(AF_INET, SOCK_STREAM, IPPROTO_IP, 0);
97
98 if (s == -1) {
Igor Sysoev72f2e362003-07-22 19:53:10 +000099 ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
Igor Sysoev6b863e32003-05-12 15:52:24 +0000100 ngx_socket_n " failed");
Igor Sysoev890fc962003-07-20 21:15:59 +0000101 return NGX_ERROR;
Igor Sysoev6b863e32003-05-12 15:52:24 +0000102 }
103
Igor Sysoev72f2e362003-07-22 19:53:10 +0000104 if (pc->rcvbuf) {
Igor Sysoev6b863e32003-05-12 15:52:24 +0000105 if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
Igor Sysoev72f2e362003-07-22 19:53:10 +0000106 (const void *) &pc->rcvbuf, sizeof(int)) == -1) {
107 ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
Igor Sysoev6b863e32003-05-12 15:52:24 +0000108 "setsockopt(SO_RCVBUF) failed");
109
110 if (ngx_close_socket(s) == -1) {
Igor Sysoev72f2e362003-07-22 19:53:10 +0000111 ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
Igor Sysoev6b863e32003-05-12 15:52:24 +0000112 ngx_close_socket_n " failed");
113 }
114
Igor Sysoev890fc962003-07-20 21:15:59 +0000115 return NGX_ERROR;
Igor Sysoev6b863e32003-05-12 15:52:24 +0000116 }
117 }
118
119 if (ngx_nonblocking(s) == -1) {
Igor Sysoev72f2e362003-07-22 19:53:10 +0000120 ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
Igor Sysoev6b863e32003-05-12 15:52:24 +0000121 ngx_nonblocking_n " failed");
122
123 if (ngx_close_socket(s) == -1) {
Igor Sysoev72f2e362003-07-22 19:53:10 +0000124 ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
Igor Sysoev6b863e32003-05-12 15:52:24 +0000125 ngx_close_socket_n " failed");
126 }
127
Igor Sysoev890fc962003-07-20 21:15:59 +0000128 return NGX_ERROR;
Igor Sysoev6b863e32003-05-12 15:52:24 +0000129 }
130
Igor Sysoev890fc962003-07-20 21:15:59 +0000131#if (WIN32)
Igor Sysoev72f2e362003-07-22 19:53:10 +0000132 /*
133 * Winsock assignes a socket number divisible by 4
134 * so to find a connection we divide a socket number by 4.
135 */
Igor Sysoev890fc962003-07-20 21:15:59 +0000136
Igor Sysoev72f2e362003-07-22 19:53:10 +0000137 if (s % 4) {
138 ngx_log_error(NGX_LOG_EMERG, pc->log, 0,
139 ngx_socket_n
140 " created socket %d, not divisible by 4", s);
141 exit(1);
142 }
Igor Sysoev890fc962003-07-20 21:15:59 +0000143
144 c = &ngx_cycle->connections[s / 4];
145 rev = &ngx_cycle->read_events[s / 4];
146 wev = &ngx_cycle->write_events[s / 4];
147
148#else
149
150 c = &ngx_cycle->connections[s];
151 rev = &ngx_cycle->read_events[s];
152 wev = &ngx_cycle->write_events[s];
153
154#endif
Igor Sysoev6b863e32003-05-12 15:52:24 +0000155
156 instance = rev->instance;
157
158 ngx_memzero(c, sizeof(ngx_connection_t));
159 ngx_memzero(rev, sizeof(ngx_event_t));
160 ngx_memzero(wev, sizeof(ngx_event_t));
161
Igor Sysoev160d7742003-11-19 16:26:41 +0000162 rev->index = NGX_INVALID_INDEX;
163 wev->index = NGX_INVALID_INDEX;
164
165 rev->data = c;
166 wev->data = c;
167
Igor Sysoev6b863e32003-05-12 15:52:24 +0000168 c->read = rev;
169 c->write = wev;
Igor Sysoevfd3e3742003-10-08 04:34:07 +0000170 wev->write = 1;
Igor Sysoev6b863e32003-05-12 15:52:24 +0000171
Igor Sysoev160d7742003-11-19 16:26:41 +0000172 rev->instance = !instance;
173 wev->instance = !instance;
Igor Sysoev6b863e32003-05-12 15:52:24 +0000174
Igor Sysoev160d7742003-11-19 16:26:41 +0000175 c->log = pc->log;
176 rev->log = pc->log;
177 wev->log = pc->log;
178
Igor Sysoev6b863e32003-05-12 15:52:24 +0000179 c->fd = s;
Igor Sysoev72f2e362003-07-22 19:53:10 +0000180
181 pc->connection = c;
182
183 if (ngx_add_conn) {
184 if (ngx_add_conn(c) == NGX_ERROR) {
185 return NGX_ERROR;
186 }
187 }
188
Igor Sysoeve6779222003-10-03 15:50:53 +0000189 ngx_memzero(&addr, sizeof(struct sockaddr_in));
190
Igor Sysoev87a01ea2003-10-02 05:39:37 +0000191 addr.sin_family = AF_INET;
Igor Sysoeve6779222003-10-03 15:50:53 +0000192 addr.sin_port = peer->port;
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000193 addr.sin_addr.s_addr = peer->addr;
Igor Sysoev3a081182003-07-23 13:10:12 +0000194
Igor Sysoev425a42c2003-10-27 16:16:17 +0000195ngx_log_debug(pc->log, "CONNECT: %s" _ peer->addr_port_text.data);
196
Igor Sysoev87a01ea2003-10-02 05:39:37 +0000197 rc = connect(s, (struct sockaddr *) &addr, sizeof(struct sockaddr_in));
Igor Sysoev3a081182003-07-23 13:10:12 +0000198
199 if (rc == -1) {
200 err = ngx_socket_errno;
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000201
202 /* Winsock returns WSAEWOULDBLOCK */
203
204 if (err != NGX_EINPROGRESS && err != NGX_EAGAIN) {
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000205 ngx_log_error(NGX_LOG_ERR, pc->log, err, "connect() failed");
Igor Sysoev3a081182003-07-23 13:10:12 +0000206
207 if (ngx_close_socket(s) == -1) {
208 ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
209 ngx_close_socket_n " failed");
210 }
211
Igor Sysoev931a4002003-10-07 15:30:05 +0000212 c->fd = -1;
213
Igor Sysoev3a081182003-07-23 13:10:12 +0000214 return NGX_CONNECT_ERROR;
215 }
216 }
217
Igor Sysoevb5faed22003-10-29 08:30:44 +0000218 if (ngx_event_flags & NGX_USE_AIO_EVENT) {
Igor Sysoevb5faed22003-10-29 08:30:44 +0000219
Igor Sysoevb5910d42003-10-30 16:51:33 +0000220 /* aio, iocp */
221
222 if (ngx_blocking(s) == -1) {
223 ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
224 ngx_blocking_n " failed");
225
226 if (ngx_close_socket(s) == -1) {
227 ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
228 ngx_close_socket_n " failed");
229 }
230
231 return NGX_ERROR;
232 }
233
234 /*
235 * aio allows to post operation on non-connected socket
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000236 * at least in FreeBSD.
237 * NT does not support it.
Igor Sysoevb5910d42003-10-30 16:51:33 +0000238 *
Igor Sysoevfe0f5cc2003-10-31 16:05:33 +0000239 * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT
Igor Sysoevb5910d42003-10-30 16:51:33 +0000240 */
241
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000242 rev->ready = 1;
Igor Sysoevb5faed22003-10-29 08:30:44 +0000243 wev->ready = 1;
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000244
Igor Sysoevb5faed22003-10-29 08:30:44 +0000245 return NGX_OK;
Igor Sysoevb5faed22003-10-29 08:30:44 +0000246 }
247
248 /* TODO: epoll */
Igor Sysoeve6779222003-10-03 15:50:53 +0000249
Igor Sysoev0a280a32003-10-12 16:49:16 +0000250 if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { /* kqueue */
Igor Sysoeve6779222003-10-03 15:50:53 +0000251 event = NGX_CLEAR_EVENT;
252
253 } else { /* select, poll, /dev/poll */
254 event = NGX_LEVEL_EVENT;
255 }
256
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000257 if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
258 return NGX_ERROR;
259 }
260
Igor Sysoeve6779222003-10-03 15:50:53 +0000261 if (rc == -1) {
262
263 /* NGX_EINPROGRESS */
264
265 if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) {
266 return NGX_ERROR;
267 }
268
269 return NGX_AGAIN;
270 }
271
Igor Sysoev222a2ad2003-11-18 16:49:00 +0000272ngx_log_debug(pc->log, "CONNECTED");
273
Igor Sysoevd404c972003-10-16 20:19:16 +0000274 wev->ready = 1;
275
Igor Sysoev87a01ea2003-10-02 05:39:37 +0000276 return NGX_OK;
Igor Sysoev890fc962003-07-20 21:15:59 +0000277}
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000278
279
280void ngx_event_connect_peer_failed(ngx_peer_connection_t *pc)
281{
Igor Sysoev219d44d2003-10-31 07:10:36 +0000282 time_t now;
283
284 now = ngx_time();
285
286 /* ngx_lock_mutex(pc->peers->mutex); */
287
288 pc->peers->peers[pc->cur_peer].fails++;
289 pc->peers->peers[pc->cur_peer].accessed = now;
290
291 /* ngx_unlock_mutex(pc->peers->mutex); */
292
Igor Sysoev425a42c2003-10-27 16:16:17 +0000293 pc->cur_peer++;
294
295 if (pc->cur_peer >= pc->peers->number) {
296 pc->cur_peer = 0;
297 }
298
Igor Sysoeve6779222003-10-03 15:50:53 +0000299 pc->tries--;
300
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000301 return;
302}