3 * Copyright (C) Igor Sysoev
7 #include <ngx_config.h>
10 #include <ngx_event_connect.h>
16 ngx_int_t
ngx_event_connect_peer(ngx_peer_connection_t
*pc
)
25 ngx_event_t
*rev
, *wev
;
27 ngx_event_conf_t
*ecf
;
28 struct sockaddr_in addr
;
32 /* ngx_lock_mutex(pc->peers->mutex); */
34 if (pc
->peers
->last_cached
) {
36 /* cached connection */
38 c
= pc
->peers
->cached
[pc
->peers
->last_cached
];
39 pc
->peers
->last_cached
--;
41 /* ngx_unlock_mutex(pc->peers->mutex); */
44 c
->read
->lock
= c
->read
->own_lock
;
45 c
->write
->lock
= c
->write
->own_lock
;
54 pc
->connection
= NULL
;
56 if (pc
->peers
->number
== 1) {
57 peer
= &pc
->peers
->peers
[0];
61 /* there are several peers */
63 if (pc
->tries
== pc
->peers
->number
) {
65 /* it's a first try - get a current peer */
67 pc
->cur_peer
= pc
->peers
->current
++;
69 if (pc
->peers
->current
>= pc
->peers
->number
) {
70 pc
->peers
->current
= 0;
74 if (pc
->peers
->max_fails
== 0) {
75 peer
= &pc
->peers
->peers
[pc
->cur_peer
];
79 /* the peers support a fault tolerance */
82 peer
= &pc
->peers
->peers
[pc
->cur_peer
];
84 if (peer
->fails
<= pc
->peers
->max_fails
) {
88 if (now
- peer
->accessed
> pc
->peers
->fail_timeout
) {
95 if (pc
->cur_peer
>= pc
->peers
->number
) {
101 if (pc
->tries
== 0) {
102 /* ngx_unlock_mutex(pc->peers->mutex); */
110 /* ngx_unlock_mutex(pc->peers->mutex); */
113 s
= ngx_socket(AF_INET
, SOCK_STREAM
, IPPROTO_IP
);
116 ngx_log_error(NGX_LOG_ALERT
, pc
->log
, ngx_socket_errno
,
117 ngx_socket_n
" failed");
122 ecf
= ngx_event_get_conf(ngx_cycle
->conf_ctx
, ngx_event_core_module
);
124 /* disable warning: Win32 SOCKET is u_int while UNIX socket is int */
126 if ((ngx_uint_t
) s
>= ecf
->connections
) {
128 ngx_log_error(NGX_LOG_ALERT
, pc
->log
, 0,
129 "socket() returned socket #%d while only %d "
130 "connections was configured, closing the socket",
131 s
, ecf
->connections
);
133 if (ngx_close_socket(s
) == -1) {
134 ngx_log_error(NGX_LOG_ALERT
, pc
->log
, ngx_socket_errno
,
135 ngx_close_socket_n
"failed");
138 /* TODO: sleep for some time */
145 if (setsockopt(s
, SOL_SOCKET
, SO_RCVBUF
,
146 (const void *) &pc
->rcvbuf
, sizeof(int)) == -1) {
147 ngx_log_error(NGX_LOG_ALERT
, pc
->log
, ngx_socket_errno
,
148 "setsockopt(SO_RCVBUF) failed");
150 if (ngx_close_socket(s
) == -1) {
151 ngx_log_error(NGX_LOG_ALERT
, pc
->log
, ngx_socket_errno
,
152 ngx_close_socket_n
" failed");
159 if (ngx_nonblocking(s
) == -1) {
160 ngx_log_error(NGX_LOG_ALERT
, pc
->log
, ngx_socket_errno
,
161 ngx_nonblocking_n
" failed");
163 if (ngx_close_socket(s
) == -1) {
164 ngx_log_error(NGX_LOG_ALERT
, pc
->log
, ngx_socket_errno
,
165 ngx_close_socket_n
" failed");
173 * Winsock assignes a socket number divisible by 4
174 * so to find a connection we divide a socket number by 4.
178 ngx_log_error(NGX_LOG_EMERG
, pc
->log
, 0,
180 " created socket %d, not divisible by 4", s
);
184 c
= &ngx_cycle
->connections
[s
/ 4];
185 rev
= &ngx_cycle
->read_events
[s
/ 4];
186 wev
= &ngx_cycle
->write_events
[s
/ 4];
190 c
= &ngx_cycle
->connections
[s
];
191 rev
= &ngx_cycle
->read_events
[s
];
192 wev
= &ngx_cycle
->write_events
[s
];
196 instance
= rev
->instance
;
201 ngx_log_debug1(NGX_LOG_DEBUG_EVENT
, pc
->log
, 0,
202 "spinlock in connect, fd:%d", s
);
203 ngx_spinlock(&c
->lock
, 1000);
204 ngx_unlock(&c
->lock
);
209 ngx_memzero(c
, sizeof(ngx_connection_t
));
210 ngx_memzero(rev
, sizeof(ngx_event_t
));
211 ngx_memzero(wev
, sizeof(ngx_event_t
));
213 rev
->instance
= !instance
;
214 wev
->instance
= !instance
;
216 rev
->index
= NGX_INVALID_INDEX
;
217 wev
->index
= NGX_INVALID_INDEX
;
232 c
->log_error
= pc
->log_error
;
237 * TODO: MT: - atomic increment (x86: lock xadd)
238 * or protection by critical section or mutex
240 * TODO: MP: - allocated in a shared memory
241 * - atomic increment (x86: lock xadd)
242 * or protection by critical section or mutex
245 c
->number
= ngx_atomic_inc(ngx_connection_counter
);
248 rev
->lock
= pc
->lock
;
249 wev
->lock
= pc
->lock
;
250 rev
->own_lock
= &c
->lock
;
251 wev
->own_lock
= &c
->lock
;
255 if (ngx_add_conn(c
) == NGX_ERROR
) {
260 ngx_memzero(&addr
, sizeof(struct sockaddr_in
));
262 addr
.sin_family
= AF_INET
;
263 addr
.sin_port
= peer
->port
;
264 addr
.sin_addr
.s_addr
= peer
->addr
;
266 ngx_log_debug2(NGX_LOG_DEBUG_EVENT
, pc
->log
, 0,
267 "connect to %V, #%d", &peer
->addr_port_text
, c
->number
);
269 rc
= connect(s
, (struct sockaddr
*) &addr
, sizeof(struct sockaddr_in
));
272 err
= ngx_socket_errno
;
274 /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */
276 if (err
!= NGX_EINPROGRESS
&& err
!= NGX_EAGAIN
) {
277 ngx_connection_error(c
, err
, "connect() failed");
279 if (ngx_close_socket(s
) == -1) {
280 ngx_log_error(NGX_LOG_ALERT
, pc
->log
, ngx_socket_errno
,
281 ngx_close_socket_n
" failed");
284 c
->fd
= (ngx_socket_t
) -1;
286 return NGX_CONNECT_ERROR
;
292 /* NGX_EINPROGRESS */
296 ngx_log_debug0(NGX_LOG_DEBUG_EVENT
, pc
->log
, 0, "connected");
300 if (ngx_event_flags
& NGX_USE_AIO_EVENT
) {
302 ngx_log_debug1(NGX_LOG_DEBUG_EVENT
, pc
->log
, ngx_socket_errno
,
303 "connect(): %d", rc
);
307 if (ngx_blocking(s
) == -1) {
308 ngx_log_error(NGX_LOG_ALERT
, pc
->log
, ngx_socket_errno
,
309 ngx_blocking_n
" failed");
311 if (ngx_close_socket(s
) == -1) {
312 ngx_log_error(NGX_LOG_ALERT
, pc
->log
, ngx_socket_errno
,
313 ngx_close_socket_n
" failed");
320 * FreeBSD aio allows to post operation on non-connected socket.
321 * NT does not support it.
323 * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT
332 if (ngx_event_flags
& NGX_USE_CLEAR_EVENT
) { /* kqueue */
333 event
= NGX_CLEAR_EVENT
;
335 } else { /* select, poll, /dev/poll */
336 event
= NGX_LEVEL_EVENT
;
339 if (ngx_add_event(rev
, NGX_READ_EVENT
, event
) != NGX_OK
) {
345 /* NGX_EINPROGRESS */
347 if (ngx_add_event(wev
, NGX_WRITE_EVENT
, event
) != NGX_OK
) {
354 ngx_log_debug0(NGX_LOG_DEBUG_EVENT
, pc
->log
, 0, "connected");
362 void ngx_event_connect_peer_failed(ngx_peer_connection_t
*pc
)
368 /* ngx_lock_mutex(pc->peers->mutex); */
370 pc
->peers
->peers
[pc
->cur_peer
].fails
++;
371 pc
->peers
->peers
[pc
->cur_peer
].accessed
= now
;
373 /* ngx_unlock_mutex(pc->peers->mutex); */
377 if (pc
->cur_peer
>= pc
->peers
->number
) {