1
2 /*
3 * Copyright (C) Roman Arutyunyan
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_event.h>
11 #include <ngx_stream.h>
12
13
14 static void ngx_stream_log_session(ngx_stream_session_t *s);
15 static void ngx_stream_close_connection(ngx_connection_t *c);
16 static u_char *ngx_stream_log_error(ngx_log_t *log, u_char *buf, size_t len);
17 static void ngx_stream_proxy_protocol_handler(ngx_event_t *rev);
18
19
20 void
ngx_stream_init_connection(ngx_connection_t * c)21 ngx_stream_init_connection(ngx_connection_t *c)
22 {
23 u_char text[NGX_SOCKADDR_STRLEN];
24 size_t len;
25 ngx_uint_t i;
26 ngx_time_t *tp;
27 ngx_event_t *rev;
28 struct sockaddr *sa;
29 ngx_stream_port_t *port;
30 struct sockaddr_in *sin;
31 ngx_stream_in_addr_t *addr;
32 ngx_stream_session_t *s;
33 ngx_stream_addr_conf_t *addr_conf;
34 #if (NGX_HAVE_INET6)
35 struct sockaddr_in6 *sin6;
36 ngx_stream_in6_addr_t *addr6;
37 #endif
38 ngx_stream_core_srv_conf_t *cscf;
39 ngx_stream_core_main_conf_t *cmcf;
40
41 /* find the server configuration for the address:port */
42
43 port = c->listening->servers;
44
45 if (port->naddrs > 1) {
46
47 /*
48 * There are several addresses on this port and one of them
49 * is the "*:port" wildcard so getsockname() is needed to determine
50 * the server address.
51 *
52 * AcceptEx() and recvmsg() already gave this address.
53 */
54
55 if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
56 ngx_stream_close_connection(c);
57 return;
58 }
59
60 sa = c->local_sockaddr;
61
62 switch (sa->sa_family) {
63
64 #if (NGX_HAVE_INET6)
65 case AF_INET6:
66 sin6 = (struct sockaddr_in6 *) sa;
67
68 addr6 = port->addrs;
69
70 /* the last address is "*" */
71
72 for (i = 0; i < port->naddrs - 1; i++) {
73 if (ngx_memcmp(&addr6[i].addr6, &sin6->sin6_addr, 16) == 0) {
74 break;
75 }
76 }
77
78 addr_conf = &addr6[i].conf;
79
80 break;
81 #endif
82
83 default: /* AF_INET */
84 sin = (struct sockaddr_in *) sa;
85
86 addr = port->addrs;
87
88 /* the last address is "*" */
89
90 for (i = 0; i < port->naddrs - 1; i++) {
91 if (addr[i].addr == sin->sin_addr.s_addr) {
92 break;
93 }
94 }
95
96 addr_conf = &addr[i].conf;
97
98 break;
99 }
100
101 } else {
102 switch (c->local_sockaddr->sa_family) {
103
104 #if (NGX_HAVE_INET6)
105 case AF_INET6:
106 addr6 = port->addrs;
107 addr_conf = &addr6[0].conf;
108 break;
109 #endif
110
111 default: /* AF_INET */
112 addr = port->addrs;
113 addr_conf = &addr[0].conf;
114 break;
115 }
116 }
117
118 s = ngx_pcalloc(c->pool, sizeof(ngx_stream_session_t));
119 if (s == NULL) {
120 ngx_stream_close_connection(c);
121 return;
122 }
123
124 s->signature = NGX_STREAM_MODULE;
125 s->main_conf = addr_conf->ctx->main_conf;
126 s->srv_conf = addr_conf->ctx->srv_conf;
127
128 #if (NGX_STREAM_SSL)
129 s->ssl = addr_conf->ssl;
130 #endif
131
132 if (c->buffer) {
133 s->received += c->buffer->last - c->buffer->pos;
134 }
135
136 s->connection = c;
137 c->data = s;
138
139 cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module);
140
141 ngx_set_connection_log(c, cscf->error_log);
142
143 len = ngx_sock_ntop(c->sockaddr, c->socklen, text, NGX_SOCKADDR_STRLEN, 1);
144
145 ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA %sclient %*s connected to %V",
146 c->number, c->type == SOCK_DGRAM ? "udp " : "",
147 len, text, &addr_conf->addr_text);
148
149 c->log->connection = c->number;
150 c->log->handler = ngx_stream_log_error;
151 c->log->data = s;
152 c->log->action = "initializing session";
153 c->log_error = NGX_ERROR_INFO;
154
155 s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_stream_max_module);
156 if (s->ctx == NULL) {
157 ngx_stream_close_connection(c);
158 return;
159 }
160
161 cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
162
163 s->variables = ngx_pcalloc(s->connection->pool,
164 cmcf->variables.nelts
165 * sizeof(ngx_stream_variable_value_t));
166
167 if (s->variables == NULL) {
168 ngx_stream_close_connection(c);
169 return;
170 }
171
172 tp = ngx_timeofday();
173 s->start_sec = tp->sec;
174 s->start_msec = tp->msec;
175
176 rev = c->read;
177 rev->handler = ngx_stream_session_handler;
178
179 if (addr_conf->proxy_protocol) {
180 c->log->action = "reading PROXY protocol";
181
182 rev->handler = ngx_stream_proxy_protocol_handler;
183
184 if (!rev->ready) {
185 ngx_add_timer(rev, cscf->proxy_protocol_timeout);
186
187 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
188 ngx_stream_finalize_session(s,
189 NGX_STREAM_INTERNAL_SERVER_ERROR);
190 }
191
192 return;
193 }
194 }
195
196 if (ngx_use_accept_mutex) {
197 ngx_post_event(rev, &ngx_posted_events);
198 return;
199 }
200
201 rev->handler(rev);
202 }
203
204
205 static void
ngx_stream_proxy_protocol_handler(ngx_event_t * rev)206 ngx_stream_proxy_protocol_handler(ngx_event_t *rev)
207 {
208 u_char *p, buf[NGX_PROXY_PROTOCOL_MAX_HEADER];
209 size_t size;
210 ssize_t n;
211 ngx_err_t err;
212 ngx_connection_t *c;
213 ngx_stream_session_t *s;
214 ngx_stream_core_srv_conf_t *cscf;
215
216 c = rev->data;
217 s = c->data;
218
219 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0,
220 "stream PROXY protocol handler");
221
222 if (rev->timedout) {
223 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
224 ngx_stream_finalize_session(s, NGX_STREAM_OK);
225 return;
226 }
227
228 n = recv(c->fd, (char *) buf, sizeof(buf), MSG_PEEK);
229
230 err = ngx_socket_errno;
231
232 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "recv(): %z", n);
233
234 if (n == -1) {
235 if (err == NGX_EAGAIN) {
236 rev->ready = 0;
237
238 if (!rev->timer_set) {
239 cscf = ngx_stream_get_module_srv_conf(s,
240 ngx_stream_core_module);
241
242 ngx_add_timer(rev, cscf->proxy_protocol_timeout);
243 }
244
245 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
246 ngx_stream_finalize_session(s,
247 NGX_STREAM_INTERNAL_SERVER_ERROR);
248 }
249
250 return;
251 }
252
253 ngx_connection_error(c, err, "recv() failed");
254
255 ngx_stream_finalize_session(s, NGX_STREAM_OK);
256 return;
257 }
258
259 if (rev->timer_set) {
260 ngx_del_timer(rev);
261 }
262
263 p = ngx_proxy_protocol_read(c, buf, buf + n);
264
265 if (p == NULL) {
266 ngx_stream_finalize_session(s, NGX_STREAM_BAD_REQUEST);
267 return;
268 }
269
270 size = p - buf;
271
272 if (c->recv(c, buf, size) != (ssize_t) size) {
273 ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
274 return;
275 }
276
277 c->log->action = "initializing session";
278
279 ngx_stream_session_handler(rev);
280 }
281
282
283 void
ngx_stream_session_handler(ngx_event_t * rev)284 ngx_stream_session_handler(ngx_event_t *rev)
285 {
286 ngx_connection_t *c;
287 ngx_stream_session_t *s;
288
289 c = rev->data;
290 s = c->data;
291
292 ngx_stream_core_run_phases(s);
293 }
294
295
296 void
ngx_stream_finalize_session(ngx_stream_session_t * s,ngx_uint_t rc)297 ngx_stream_finalize_session(ngx_stream_session_t *s, ngx_uint_t rc)
298 {
299 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
300 "finalize stream session: %i", rc);
301
302 s->status = rc;
303
304 ngx_stream_log_session(s);
305
306 ngx_stream_close_connection(s->connection);
307 }
308
309
310 static void
ngx_stream_log_session(ngx_stream_session_t * s)311 ngx_stream_log_session(ngx_stream_session_t *s)
312 {
313 ngx_uint_t i, n;
314 ngx_stream_handler_pt *log_handler;
315 ngx_stream_core_main_conf_t *cmcf;
316
317 cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
318
319 log_handler = cmcf->phases[NGX_STREAM_LOG_PHASE].handlers.elts;
320 n = cmcf->phases[NGX_STREAM_LOG_PHASE].handlers.nelts;
321
322 for (i = 0; i < n; i++) {
323 log_handler[i](s);
324 }
325 }
326
327
328 static void
ngx_stream_close_connection(ngx_connection_t * c)329 ngx_stream_close_connection(ngx_connection_t *c)
330 {
331 ngx_pool_t *pool;
332
333 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
334 "close stream connection: %d", c->fd);
335
336 #if (NGX_STREAM_SSL)
337
338 if (c->ssl) {
339 if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
340 c->ssl->handler = ngx_stream_close_connection;
341 return;
342 }
343 }
344
345 #endif
346
347 #if (NGX_STAT_STUB)
348 (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
349 #endif
350
351 pool = c->pool;
352
353 ngx_close_connection(c);
354
355 ngx_destroy_pool(pool);
356 }
357
358
359 static u_char *
ngx_stream_log_error(ngx_log_t * log,u_char * buf,size_t len)360 ngx_stream_log_error(ngx_log_t *log, u_char *buf, size_t len)
361 {
362 u_char *p;
363 ngx_stream_session_t *s;
364
365 if (log->action) {
366 p = ngx_snprintf(buf, len, " while %s", log->action);
367 len -= p - buf;
368 buf = p;
369 }
370
371 s = log->data;
372
373 p = ngx_snprintf(buf, len, ", %sclient: %V, server: %V",
374 s->connection->type == SOCK_DGRAM ? "udp " : "",
375 &s->connection->addr_text,
376 &s->connection->listening->addr_text);
377 len -= p - buf;
378 buf = p;
379
380 if (s->log_handler) {
381 p = s->log_handler(log, buf, len);
382 }
383
384 return p;
385 }
386