001void
002ngx_event_accept(ngx_event_t *ev)
003{
004socklen_t socklen;
005ngx_err_t err;
006ngx_log_t *log;
007ngx_uint_t level;
008ngx_socket_t s;
009ngx_event_t *rev, *wev;
010ngx_listening_t *ls;
011ngx_connection_t *c, *lc;
012ngx_event_conf_t *ecf;
013u_char sa[NGX_SOCKADDRLEN];
014
015if (ev->timedout) {
016if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) {
017return;
018}
019
020ev->timedout = 0;
021}
022
023ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module);
024
025if (ngx_event_flags & NGX_USE_RTSIG_EVENT) {
026ev->available = 1;
027
028} else if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) {
029ev->available = ecf->multi_accept;
030}
031
032lc = ev->data;
033ls = lc->listening;
034ev->ready = 0;
035
036do {
037socklen = NGX_SOCKADDRLEN;
038
039/* 1、accept方法试图建立连接,非阻塞调用 */
040s = accept(lc->fd, (struct sockaddr *) sa, &socklen);
041
042if (s == (ngx_socket_t) -1)
043{
044err = ngx_socket_errno;
045
046if (err == NGX_EAGAIN)
047{
048/* 没有连接,直接返回 */
049return;
050}
051
052level = NGX_LOG_ALERT;
053
054if (err == NGX_ECONNABORTED) {
055level = NGX_LOG_ERR;
056
057} else if (err == NGX_EMFILE || err == NGX_ENFILE) {
058level = NGX_LOG_CRIT;
059}
060
061if (err == NGX_ECONNABORTED) {
062if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
063ev->available–;
064}
065
066if (ev->available) {
067continue;
068}
069}
070
071if (err == NGX_EMFILE || err == NGX_ENFILE) {
072if (ngx_disable_accept_events((ngx_cycle_t *) ngx_cycle)
073!= NGX_OK)
074{
075return;
076}
077
078if (ngx_use_accept_mutex) {
079if (ngx_accept_mutex_held) {
080ngx_shmtx_unlock(&ngx_accept_mutex);
081ngx_accept_mutex_held = 0;
082}
083
084ngx_accept_disabled = 1;
085
086} else {
087ngx_add_timer(ev, ecf->accept_mutex_delay);
088}
089}
090
091return;
092}
093
094/* 2、设置负载均衡阈值 */
095ngx_accept_disabled = ngx_cycle->connection_n / 8
096- ngx_cycle->free_connection_n;
097
098/* 3、从连接池获得一个连接对象 */
099c = ngx_get_connection(s, ev->log);
100
101/* 4、为连接创建内存池 */
102c->pool = ngx_create_pool(ls->pool_size, ev->log);
103
104c->sockaddr = ngx_palloc(c->pool, socklen);
105
106ngx_memcpy(c->sockaddr, sa, socklen);
107
108log = ngx_palloc(c->pool, sizeof(ngx_log_t));
109
110/* set a blocking mode for aio and non-blocking mode for others */
111/* 5、设置套接字属性为阻塞或非阻塞 */
112if (ngx_inherited_nonblocking) {
113if (ngx_event_flags & NGX_USE_AIO_EVENT) {
114if (ngx_blocking(s) == -1) {
115ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
116ngx_blocking_n ” failed”);
117ngx_close_accepted_connection(c);
118return;
119}
120}
121
122} else {
123if (!(ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT))) {
124if (ngx_nonblocking(s) == -1) {
125ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
126ngx_nonblocking_n ” failed”);
127ngx_close_accepted_connection(c);
128return;
129}
130}
131}
132
133*log = ls->log;
134
135c->recv = ngx_recv;
136c->send = ngx_send;
137c->recv_chain = ngx_recv_chain;
138c->send_chain = ngx_send_chain;
139
140c->log = log;
141c->pool->log = log;
142
143c->socklen = socklen;
144c->listening = ls;
145c->local_sockaddr = ls->sockaddr;
146c->local_socklen = ls->socklen;
147
148c->unexpected_eof = 1;
149
150rev = c->read;
151wev = c->write;
152
153wev->ready = 1;
154
155if (ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT)) {
156/* rtsig, aio, iocp */
157rev->ready = 1;
158}
159
160if (ev->deferred_accept) {
161rev->ready = 1;
162
163}
164
165rev->log = log;
166wev->log = log;
167
168/*
169* TODO: MT: – ngx_atomic_fetch_add()
170* or protection by critical section or light mutex
171*
172* TODO: MP: – allocated in a shared memory
173* – ngx_atomic_fetch_add()
174* or protection by critical section or light mutex
175*/
176
177c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
178
179if (ls->addr_ntop) {
180c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len);
181if (c->addr_text.data == NULL) {
182ngx_close_accepted_connection(c);
183return;
184}
185
186c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen,
187c->addr_text.data,
188ls->addr_text_max_len, 0);
189if (c->addr_text.len == 0) {
190ngx_close_accepted_connection(c);
191return;
192}
193}
194
195/* 6、将新连接对应的读写事件添加到epoll对象中 */
196if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {
197if (ngx_add_conn(c) == NGX_ERROR) {
198ngx_close_accepted_connection(c);
199return;
200}
201}
202
203log->data = NULL;
204log->handler = NULL;
205
206/* 7、TCP建立成功调用的方法,这个方法在ngx_listening_t结构体中 */
207ls->handler(c);
208
209} while (ev->available); /* available标志表示一次尽可能多的建立连接,由配置项multi_accept决定 */
210}