微信公眾號:鄭爾多斯
關注可瞭解更多的Nginx知識。任何問題或建議,請公眾號留言;
關注公眾號,有趣有內涵的文章第一時間送達!
ngx_open_listening_sockets
1ngx_int_t
2ngx_open_listening_sockets(ngx_cycle_t *cycle)
3{
4 int reuseaddr;
5 ngx_uint_t i, tries, failed;
6 ngx_err_t err;
7 ngx_log_t *log;
8 ngx_socket_t s;
9 ngx_listening_t *ls;
10
11 reuseaddr = 1;
12#if (NGX_SUPPRESS_WARN)
13 failed = 0;
14#endif
15
16 log = cycle->log;
17
18 /* TODO: configurable try number */
19
20 for (tries = 5; tries; tries--) {
21 failed = 0;
22
23 /* for each listening socket */
24
25 ls = cycle->listening.elts;
26 for (i = 0; i < cycle->listening.nelts; i++) {
27
28 if (ls[i].ignore) {
29 continue;
30 }
31
32#if (NGX_HAVE_REUSEPORT)
33
34 if (ls[i].add_reuseport) {
35
36 /*
37 * to allow transition from a socket without SO_REUSEPORT
38 * to multiple sockets with SO_REUSEPORT, we have to set
39 * SO_REUSEPORT on the old socket before opening new ones
40 */
41
42 int reuseport = 1;
43
44 if (setsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT,
45 (const void *) &reuseport, sizeof(int))
46 == -1)
47 {
48 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
49 "setsockopt(SO_REUSEPORT) %V failed, ignored",
50 &ls[i].addr_text);
51 }
52
53 ls[i].add_reuseport = 0;
54 }
55#endif
56
57 if (ls[i].fd != (ngx_socket_t) -1) {
58 continue;
59 }
60
61 if (ls[i].inherited) {
62
63 /* TODO: close on exit */
64 /* TODO: nonblocking */
65 /* TODO: deferred accept */
66
67 continue;
68 }
69
70 s = ngx_socket(ls[i].sockaddr->sa_family, ls[i].type, 0);
71
72 if (s == (ngx_socket_t) -1) {
73 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
74 ngx_socket_n " %V failed", &ls[i].addr_text);
75 return NGX_ERROR;
76 }
77
78 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
79 (const void *) &reuseaddr, sizeof(int))
80 == -1)
81 {
82 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
83 "setsockopt(SO_REUSEADDR) %V failed",
84 &ls[i].addr_text);
85
86 if (ngx_close_socket(s) == -1) {
87 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
88 ngx_close_socket_n " %V failed",
89 &ls[i].addr_text);
90 }
91
92 return NGX_ERROR;
93 }
94
95#if (NGX_HAVE_REUSEPORT)
96
97 if (ls[i].reuseport && !ngx_test_config) {
98 int reuseport;
99
100 reuseport = 1;
101
102 if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT,
103 (const void *) &reuseport, sizeof(int))
104 == -1)
105 {
106 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
107 "setsockopt(SO_REUSEPORT) %V failed",
108 &ls[i].addr_text);
109
110 if (ngx_close_socket(s) == -1) {
111 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
112 ngx_close_socket_n " %V failed",
113 &ls[i].addr_text);
114 }
115
116 return NGX_ERROR;
117 }
118 }
119#endif
120
121#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
122
123 if (ls[i].sockaddr->sa_family == AF_INET6) {
124 int ipv6only;
125
126 ipv6only = ls[i].ipv6only;
127
128 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
129 (const void *) &ipv6only, sizeof(int))
130 == -1)
131 {
132 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
133 "setsockopt(IPV6_V6ONLY) %V failed, ignored",
134 &ls[i].addr_text);
135 }
136 }
137#endif
138 /* TODO: close on exit */
139
140 if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) {
141 if (ngx_nonblocking(s) == -1) {
142 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
143 ngx_nonblocking_n " %V failed",
144 &ls[i].addr_text);
145
146 if (ngx_close_socket(s) == -1) {
147 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
148 ngx_close_socket_n " %V failed",
149 &ls[i].addr_text);
150 }
151
152 return NGX_ERROR;
153 }
154 }
155
156 ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0,
157 "bind() %V #%d ", &ls[i].addr_text, s);
158
159 if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) {
160 err = ngx_socket_errno;
161
162 if (err != NGX_EADDRINUSE || !ngx_test_config) {
163 ngx_log_error(NGX_LOG_EMERG, log, err,
164 "bind() to %V failed", &ls[i].addr_text);
165 }
166
167 if (ngx_close_socket(s) == -1) {
168 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
169 ngx_close_socket_n " %V failed",
170 &ls[i].addr_text);
171 }
172
173 if (err != NGX_EADDRINUSE) {
174 return NGX_ERROR;
175 }
176
177 if (!ngx_test_config) {
178 failed = 1;
179 }
180
181 continue;
182 }
183
184#if (NGX_HAVE_UNIX_DOMAIN)
185
186 if (ls[i].sockaddr->sa_family == AF_UNIX) {
187 mode_t mode;
188 u_char *name;
189
190 name = ls[i].addr_text.data + sizeof("unix:") - 1;
191 mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
192
193 if (chmod((char *) name, mode) == -1) {
194 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
195 "chmod() \"%s\" failed", name);
196 }
197
198 if (ngx_test_config) {
199 if (ngx_delete_file(name) == NGX_FILE_ERROR) {
200 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
201 ngx_delete_file_n " %s failed", name);
202 }
203 }
204 }
205#endif
206
207 if (ls[i].type != SOCK_STREAM) {
208 ls[i].fd = s;
209 continue;
210 }
211
212 if (listen(s, ls[i].backlog) == -1) {
213 err = ngx_socket_errno;
214
215 /*
216 * on OpenVZ after suspend/resume EADDRINUSE
217 * may be returned by listen() instead of bind(), see
218 * https://bugzilla.openvz.org/show_bug.cgi?id=2470
219 */
220
221 if (err != NGX_EADDRINUSE || !ngx_test_config) {
222 ngx_log_error(NGX_LOG_EMERG, log, err,
223 "listen() to %V, backlog %d failed",
224 &ls[i].addr_text, ls[i].backlog);
225 }
226
227 if (ngx_close_socket(s) == -1) {
228 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
229 ngx_close_socket_n " %V failed",
230 &ls[i].addr_text);
231 }
232
233 if (err != NGX_EADDRINUSE) {
234 return NGX_ERROR;
235 }
236
237 if (!ngx_test_config) {
238 failed = 1;
239 }
240
241 continue;
242 }
243
244 ls[i].listen = 1;
245
246 ls[i].fd = s;
247 }
248
249 if (!failed) {
250 break;
251 }
252
253 /* TODO: delay configurable */
254
255 ngx_log_error(NGX_LOG_NOTICE, log, 0,
256 "try again to bind() after 500ms");
257
258 ngx_msleep(500);
259 }
260
261 if (failed) {
262 ngx_log_error(NGX_LOG_EMERG, log, 0, "still could not bind()");
263 return NGX_ERROR;
264 }
265
266 return NGX_OK;
267}
複製程式碼
這個函式的功能很簡單,就是開啟socket,然後bind,然後listen,僅此而已,通過這個函式,我麼已經對這個埠和IP地址進行了listen,當有新的連線的時候,就會accept新的連線。
記憶體佈局如下:
喜歡本文的朋友們,歡迎長按下圖關注訂閱號鄭爾多斯,更多精彩內容第一時間送達