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_stream.h>
11
12
13 static ngx_int_t ngx_stream_core_preconfiguration(ngx_conf_t *cf);
14 static void *ngx_stream_core_create_main_conf(ngx_conf_t *cf);
15 static char *ngx_stream_core_init_main_conf(ngx_conf_t *cf, void *conf);
16 static void *ngx_stream_core_create_srv_conf(ngx_conf_t *cf);
17 static char *ngx_stream_core_merge_srv_conf(ngx_conf_t *cf, void *parent,
18 void *child);
19 static char *ngx_stream_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd,
20 void *conf);
21 static char *ngx_stream_core_server(ngx_conf_t *cf, ngx_command_t *cmd,
22 void *conf);
23 static char *ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd,
24 void *conf);
25 static char *ngx_stream_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd,
26 void *conf);
27
28
29 static ngx_command_t ngx_stream_core_commands[] = {
30
31 { ngx_string("variables_hash_max_size"),
32 NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1,
33 ngx_conf_set_num_slot,
34 NGX_STREAM_MAIN_CONF_OFFSET,
35 offsetof(ngx_stream_core_main_conf_t, variables_hash_max_size),
36 NULL },
37
38 { ngx_string("variables_hash_bucket_size"),
39 NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1,
40 ngx_conf_set_num_slot,
41 NGX_STREAM_MAIN_CONF_OFFSET,
42 offsetof(ngx_stream_core_main_conf_t, variables_hash_bucket_size),
43 NULL },
44
45 { ngx_string("server"),
46 NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
47 ngx_stream_core_server,
48 0,
49 0,
50 NULL },
51
52 { ngx_string("listen"),
53 NGX_STREAM_SRV_CONF|NGX_CONF_1MORE,
54 ngx_stream_core_listen,
55 NGX_STREAM_SRV_CONF_OFFSET,
56 0,
57 NULL },
58
59 #if (NGX_HAVE_FSTACK)
60 { ngx_string("kernel_network_stack"),
61 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG,
62 ngx_conf_set_flag_slot,
63 NGX_STREAM_SRV_CONF_OFFSET,
64 offsetof(ngx_stream_core_srv_conf_t, kernel_network_stack),
65 NULL },
66 #endif
67
68 { ngx_string("error_log"),
69 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE,
70 ngx_stream_core_error_log,
71 NGX_STREAM_SRV_CONF_OFFSET,
72 0,
73 NULL },
74
75 { ngx_string("resolver"),
76 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE,
77 ngx_stream_core_resolver,
78 NGX_STREAM_SRV_CONF_OFFSET,
79 0,
80 NULL },
81
82 { ngx_string("resolver_timeout"),
83 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
84 ngx_conf_set_msec_slot,
85 NGX_STREAM_SRV_CONF_OFFSET,
86 offsetof(ngx_stream_core_srv_conf_t, resolver_timeout),
87 NULL },
88
89 { ngx_string("proxy_protocol_timeout"),
90 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
91 ngx_conf_set_msec_slot,
92 NGX_STREAM_SRV_CONF_OFFSET,
93 offsetof(ngx_stream_core_srv_conf_t, proxy_protocol_timeout),
94 NULL },
95
96 { ngx_string("tcp_nodelay"),
97 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG,
98 ngx_conf_set_flag_slot,
99 NGX_STREAM_SRV_CONF_OFFSET,
100 offsetof(ngx_stream_core_srv_conf_t, tcp_nodelay),
101 NULL },
102
103 { ngx_string("preread_buffer_size"),
104 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
105 ngx_conf_set_size_slot,
106 NGX_STREAM_SRV_CONF_OFFSET,
107 offsetof(ngx_stream_core_srv_conf_t, preread_buffer_size),
108 NULL },
109
110 { ngx_string("preread_timeout"),
111 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
112 ngx_conf_set_msec_slot,
113 NGX_STREAM_SRV_CONF_OFFSET,
114 offsetof(ngx_stream_core_srv_conf_t, preread_timeout),
115 NULL },
116
117 ngx_null_command
118 };
119
120
121 static ngx_stream_module_t ngx_stream_core_module_ctx = {
122 ngx_stream_core_preconfiguration, /* preconfiguration */
123 NULL, /* postconfiguration */
124
125 ngx_stream_core_create_main_conf, /* create main configuration */
126 ngx_stream_core_init_main_conf, /* init main configuration */
127
128 ngx_stream_core_create_srv_conf, /* create server configuration */
129 ngx_stream_core_merge_srv_conf /* merge server configuration */
130 };
131
132
133 ngx_module_t ngx_stream_core_module = {
134 NGX_MODULE_V1,
135 &ngx_stream_core_module_ctx, /* module context */
136 ngx_stream_core_commands, /* module directives */
137 NGX_STREAM_MODULE, /* module type */
138 NULL, /* init master */
139 NULL, /* init module */
140 NULL, /* init process */
141 NULL, /* init thread */
142 NULL, /* exit thread */
143 NULL, /* exit process */
144 NULL, /* exit master */
145 NGX_MODULE_V1_PADDING
146 };
147
148
149 void
ngx_stream_core_run_phases(ngx_stream_session_t * s)150 ngx_stream_core_run_phases(ngx_stream_session_t *s)
151 {
152 ngx_int_t rc;
153 ngx_stream_phase_handler_t *ph;
154 ngx_stream_core_main_conf_t *cmcf;
155
156 cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
157
158 ph = cmcf->phase_engine.handlers;
159
160 while (ph[s->phase_handler].checker) {
161
162 rc = ph[s->phase_handler].checker(s, &ph[s->phase_handler]);
163
164 if (rc == NGX_OK) {
165 return;
166 }
167 }
168 }
169
170
171 ngx_int_t
ngx_stream_core_generic_phase(ngx_stream_session_t * s,ngx_stream_phase_handler_t * ph)172 ngx_stream_core_generic_phase(ngx_stream_session_t *s,
173 ngx_stream_phase_handler_t *ph)
174 {
175 ngx_int_t rc;
176
177 /*
178 * generic phase checker,
179 * used by all phases, except for preread and content
180 */
181
182 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
183 "generic phase: %ui", s->phase_handler);
184
185 rc = ph->handler(s);
186
187 if (rc == NGX_OK) {
188 s->phase_handler = ph->next;
189 return NGX_AGAIN;
190 }
191
192 if (rc == NGX_DECLINED) {
193 s->phase_handler++;
194 return NGX_AGAIN;
195 }
196
197 if (rc == NGX_AGAIN || rc == NGX_DONE) {
198 return NGX_OK;
199 }
200
201 if (rc == NGX_ERROR) {
202 rc = NGX_STREAM_INTERNAL_SERVER_ERROR;
203 }
204
205 ngx_stream_finalize_session(s, rc);
206
207 return NGX_OK;
208 }
209
210
211 ngx_int_t
ngx_stream_core_preread_phase(ngx_stream_session_t * s,ngx_stream_phase_handler_t * ph)212 ngx_stream_core_preread_phase(ngx_stream_session_t *s,
213 ngx_stream_phase_handler_t *ph)
214 {
215 size_t size;
216 ssize_t n;
217 ngx_int_t rc;
218 ngx_connection_t *c;
219 ngx_stream_core_srv_conf_t *cscf;
220
221 c = s->connection;
222
223 c->log->action = "prereading client data";
224
225 cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module);
226
227 if (c->read->timedout) {
228 rc = NGX_STREAM_OK;
229
230 } else if (c->read->timer_set) {
231 rc = NGX_AGAIN;
232
233 } else {
234 rc = ph->handler(s);
235 }
236
237 while (rc == NGX_AGAIN) {
238
239 if (c->buffer == NULL) {
240 c->buffer = ngx_create_temp_buf(c->pool, cscf->preread_buffer_size);
241 if (c->buffer == NULL) {
242 rc = NGX_ERROR;
243 break;
244 }
245 }
246
247 size = c->buffer->end - c->buffer->last;
248
249 if (size == 0) {
250 ngx_log_error(NGX_LOG_ERR, c->log, 0, "preread buffer full");
251 rc = NGX_STREAM_BAD_REQUEST;
252 break;
253 }
254
255 if (c->read->eof) {
256 rc = NGX_STREAM_OK;
257 break;
258 }
259
260 if (!c->read->ready) {
261 break;
262 }
263
264 n = c->recv(c, c->buffer->last, size);
265
266 if (n == NGX_ERROR || n == 0) {
267 rc = NGX_STREAM_OK;
268 break;
269 }
270
271 if (n == NGX_AGAIN) {
272 break;
273 }
274
275 c->buffer->last += n;
276
277 rc = ph->handler(s);
278 }
279
280 if (rc == NGX_AGAIN) {
281 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
282 ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
283 return NGX_OK;
284 }
285
286 if (!c->read->timer_set) {
287 ngx_add_timer(c->read, cscf->preread_timeout);
288 }
289
290 c->read->handler = ngx_stream_session_handler;
291
292 return NGX_OK;
293 }
294
295 if (c->read->timer_set) {
296 ngx_del_timer(c->read);
297 }
298
299 if (rc == NGX_OK) {
300 s->phase_handler = ph->next;
301 return NGX_AGAIN;
302 }
303
304 if (rc == NGX_DECLINED) {
305 s->phase_handler++;
306 return NGX_AGAIN;
307 }
308
309 if (rc == NGX_DONE) {
310 return NGX_OK;
311 }
312
313 if (rc == NGX_ERROR) {
314 rc = NGX_STREAM_INTERNAL_SERVER_ERROR;
315 }
316
317 ngx_stream_finalize_session(s, rc);
318
319 return NGX_OK;
320 }
321
322
323 ngx_int_t
ngx_stream_core_content_phase(ngx_stream_session_t * s,ngx_stream_phase_handler_t * ph)324 ngx_stream_core_content_phase(ngx_stream_session_t *s,
325 ngx_stream_phase_handler_t *ph)
326 {
327 ngx_connection_t *c;
328 ngx_stream_core_srv_conf_t *cscf;
329
330 c = s->connection;
331
332 c->log->action = NULL;
333
334 cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module);
335
336 if (c->type == SOCK_STREAM
337 && cscf->tcp_nodelay
338 && ngx_tcp_nodelay(c) != NGX_OK)
339 {
340 ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
341 return NGX_OK;
342 }
343
344 cscf->handler(s);
345
346 return NGX_OK;
347 }
348
349
350 static ngx_int_t
ngx_stream_core_preconfiguration(ngx_conf_t * cf)351 ngx_stream_core_preconfiguration(ngx_conf_t *cf)
352 {
353 return ngx_stream_variables_add_core_vars(cf);
354 }
355
356
357 static void *
ngx_stream_core_create_main_conf(ngx_conf_t * cf)358 ngx_stream_core_create_main_conf(ngx_conf_t *cf)
359 {
360 ngx_stream_core_main_conf_t *cmcf;
361
362 cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_core_main_conf_t));
363 if (cmcf == NULL) {
364 return NULL;
365 }
366
367 if (ngx_array_init(&cmcf->servers, cf->pool, 4,
368 sizeof(ngx_stream_core_srv_conf_t *))
369 != NGX_OK)
370 {
371 return NULL;
372 }
373
374 if (ngx_array_init(&cmcf->listen, cf->pool, 4, sizeof(ngx_stream_listen_t))
375 != NGX_OK)
376 {
377 return NULL;
378 }
379
380 cmcf->variables_hash_max_size = NGX_CONF_UNSET_UINT;
381 cmcf->variables_hash_bucket_size = NGX_CONF_UNSET_UINT;
382
383 return cmcf;
384 }
385
386
387 static char *
ngx_stream_core_init_main_conf(ngx_conf_t * cf,void * conf)388 ngx_stream_core_init_main_conf(ngx_conf_t *cf, void *conf)
389 {
390 ngx_stream_core_main_conf_t *cmcf = conf;
391
392 ngx_conf_init_uint_value(cmcf->variables_hash_max_size, 1024);
393 ngx_conf_init_uint_value(cmcf->variables_hash_bucket_size, 64);
394
395 cmcf->variables_hash_bucket_size =
396 ngx_align(cmcf->variables_hash_bucket_size, ngx_cacheline_size);
397
398 if (cmcf->ncaptures) {
399 cmcf->ncaptures = (cmcf->ncaptures + 1) * 3;
400 }
401
402 return NGX_CONF_OK;
403 }
404
405
406 static void *
ngx_stream_core_create_srv_conf(ngx_conf_t * cf)407 ngx_stream_core_create_srv_conf(ngx_conf_t *cf)
408 {
409 ngx_stream_core_srv_conf_t *cscf;
410
411 cscf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_core_srv_conf_t));
412 if (cscf == NULL) {
413 return NULL;
414 }
415
416 /*
417 * set by ngx_pcalloc():
418 *
419 * cscf->handler = NULL;
420 * cscf->error_log = NULL;
421 */
422
423 cscf->file_name = cf->conf_file->file.name.data;
424 cscf->line = cf->conf_file->line;
425 cscf->resolver_timeout = NGX_CONF_UNSET_MSEC;
426 cscf->proxy_protocol_timeout = NGX_CONF_UNSET_MSEC;
427 cscf->tcp_nodelay = NGX_CONF_UNSET;
428 cscf->preread_buffer_size = NGX_CONF_UNSET_SIZE;
429 cscf->preread_timeout = NGX_CONF_UNSET_MSEC;
430
431 #if (NGX_HAVE_FSTACK)
432 cscf->kernel_network_stack = NGX_CONF_UNSET;
433 #endif
434
435 return cscf;
436 }
437
438
439 static char *
ngx_stream_core_merge_srv_conf(ngx_conf_t * cf,void * parent,void * child)440 ngx_stream_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
441 {
442 ngx_stream_core_srv_conf_t *prev = parent;
443 ngx_stream_core_srv_conf_t *conf = child;
444
445 ngx_conf_merge_msec_value(conf->resolver_timeout,
446 prev->resolver_timeout, 30000);
447
448 if (conf->resolver == NULL) {
449
450 if (prev->resolver == NULL) {
451
452 /*
453 * create dummy resolver in stream {} context
454 * to inherit it in all servers
455 */
456
457 prev->resolver = ngx_resolver_create(cf, NULL, 0);
458 if (prev->resolver == NULL) {
459 return NGX_CONF_ERROR;
460 }
461 }
462
463 conf->resolver = prev->resolver;
464 }
465
466 if (conf->handler == NULL) {
467 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
468 "no handler for server in %s:%ui",
469 conf->file_name, conf->line);
470 return NGX_CONF_ERROR;
471 }
472
473 if (conf->error_log == NULL) {
474 if (prev->error_log) {
475 conf->error_log = prev->error_log;
476 } else {
477 conf->error_log = &cf->cycle->new_log;
478 }
479 }
480
481 ngx_conf_merge_msec_value(conf->proxy_protocol_timeout,
482 prev->proxy_protocol_timeout, 30000);
483
484 ngx_conf_merge_value(conf->tcp_nodelay, prev->tcp_nodelay, 1);
485
486 ngx_conf_merge_size_value(conf->preread_buffer_size,
487 prev->preread_buffer_size, 16384);
488
489 ngx_conf_merge_msec_value(conf->preread_timeout,
490 prev->preread_timeout, 30000);
491
492 #if (NGX_HAVE_FSTACK)
493 /* By default, we set up a server on fstack */
494 ngx_conf_merge_value(conf->kernel_network_stack,
495 prev->kernel_network_stack, 0);
496 #endif
497
498 return NGX_CONF_OK;
499 }
500
501
502 static char *
ngx_stream_core_error_log(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)503 ngx_stream_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
504 {
505 ngx_stream_core_srv_conf_t *cscf = conf;
506
507 return ngx_log_set_log(cf, &cscf->error_log);
508 }
509
510
511 static char *
ngx_stream_core_server(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)512 ngx_stream_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
513 {
514 char *rv;
515 void *mconf;
516 ngx_uint_t m;
517 ngx_conf_t pcf;
518 ngx_stream_module_t *module;
519 ngx_stream_conf_ctx_t *ctx, *stream_ctx;
520 ngx_stream_core_srv_conf_t *cscf, **cscfp;
521 ngx_stream_core_main_conf_t *cmcf;
522
523 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_stream_conf_ctx_t));
524 if (ctx == NULL) {
525 return NGX_CONF_ERROR;
526 }
527
528 stream_ctx = cf->ctx;
529 ctx->main_conf = stream_ctx->main_conf;
530
531 /* the server{}'s srv_conf */
532
533 ctx->srv_conf = ngx_pcalloc(cf->pool,
534 sizeof(void *) * ngx_stream_max_module);
535 if (ctx->srv_conf == NULL) {
536 return NGX_CONF_ERROR;
537 }
538
539 for (m = 0; cf->cycle->modules[m]; m++) {
540 if (cf->cycle->modules[m]->type != NGX_STREAM_MODULE) {
541 continue;
542 }
543
544 module = cf->cycle->modules[m]->ctx;
545
546 if (module->create_srv_conf) {
547 mconf = module->create_srv_conf(cf);
548 if (mconf == NULL) {
549 return NGX_CONF_ERROR;
550 }
551
552 ctx->srv_conf[cf->cycle->modules[m]->ctx_index] = mconf;
553 }
554 }
555
556 /* the server configuration context */
557
558 cscf = ctx->srv_conf[ngx_stream_core_module.ctx_index];
559 cscf->ctx = ctx;
560
561 cmcf = ctx->main_conf[ngx_stream_core_module.ctx_index];
562
563 cscfp = ngx_array_push(&cmcf->servers);
564 if (cscfp == NULL) {
565 return NGX_CONF_ERROR;
566 }
567
568 *cscfp = cscf;
569
570
571 /* parse inside server{} */
572
573 pcf = *cf;
574 cf->ctx = ctx;
575 cf->cmd_type = NGX_STREAM_SRV_CONF;
576
577 rv = ngx_conf_parse(cf, NULL);
578
579 *cf = pcf;
580
581 if (rv == NGX_CONF_OK && !cscf->listen) {
582 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
583 "no \"listen\" is defined for server in %s:%ui",
584 cscf->file_name, cscf->line);
585 return NGX_CONF_ERROR;
586 }
587
588 return rv;
589 }
590
591
592 static char *
ngx_stream_core_listen(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)593 ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
594 {
595 ngx_stream_core_srv_conf_t *cscf = conf;
596
597 ngx_str_t *value, size;
598 ngx_url_t u;
599 ngx_uint_t i, n, backlog;
600 ngx_stream_listen_t *ls, *als;
601 ngx_stream_core_main_conf_t *cmcf;
602
603 cscf->listen = 1;
604
605 value = cf->args->elts;
606
607 ngx_memzero(&u, sizeof(ngx_url_t));
608
609 u.url = value[1];
610 u.listen = 1;
611
612 if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
613 if (u.err) {
614 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
615 "%s in \"%V\" of the \"listen\" directive",
616 u.err, &u.url);
617 }
618
619 return NGX_CONF_ERROR;
620 }
621
622 cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
623
624 ls = ngx_array_push_n(&cmcf->listen, u.naddrs);
625 if (ls == NULL) {
626 return NGX_CONF_ERROR;
627 }
628
629 ngx_memzero(ls, sizeof(ngx_stream_listen_t));
630
631 ls->backlog = NGX_LISTEN_BACKLOG;
632 ls->rcvbuf = -1;
633 ls->sndbuf = -1;
634 ls->type = SOCK_STREAM;
635 ls->ctx = cf->ctx;
636
637 #if (NGX_HAVE_INET6)
638 ls->ipv6only = 1;
639 #endif
640
641 backlog = 0;
642
643 for (i = 2; i < cf->args->nelts; i++) {
644
645 #if !(NGX_WIN32)
646 if (ngx_strcmp(value[i].data, "udp") == 0) {
647 ls->type = SOCK_DGRAM;
648 continue;
649 }
650 #endif
651
652 if (ngx_strcmp(value[i].data, "bind") == 0) {
653 ls->bind = 1;
654 continue;
655 }
656
657 if (ngx_strncmp(value[i].data, "backlog=", 8) == 0) {
658 ls->backlog = ngx_atoi(value[i].data + 8, value[i].len - 8);
659 ls->bind = 1;
660
661 if (ls->backlog == NGX_ERROR || ls->backlog == 0) {
662 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
663 "invalid backlog \"%V\"", &value[i]);
664 return NGX_CONF_ERROR;
665 }
666
667 backlog = 1;
668
669 continue;
670 }
671
672 if (ngx_strncmp(value[i].data, "rcvbuf=", 7) == 0) {
673 size.len = value[i].len - 7;
674 size.data = value[i].data + 7;
675
676 ls->rcvbuf = ngx_parse_size(&size);
677 ls->bind = 1;
678
679 if (ls->rcvbuf == NGX_ERROR) {
680 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
681 "invalid rcvbuf \"%V\"", &value[i]);
682 return NGX_CONF_ERROR;
683 }
684
685 continue;
686 }
687
688 if (ngx_strncmp(value[i].data, "sndbuf=", 7) == 0) {
689 size.len = value[i].len - 7;
690 size.data = value[i].data + 7;
691
692 ls->sndbuf = ngx_parse_size(&size);
693 ls->bind = 1;
694
695 if (ls->sndbuf == NGX_ERROR) {
696 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
697 "invalid sndbuf \"%V\"", &value[i]);
698 return NGX_CONF_ERROR;
699 }
700
701 continue;
702 }
703
704 if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) {
705 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
706 if (ngx_strcmp(&value[i].data[10], "n") == 0) {
707 ls->ipv6only = 1;
708
709 } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) {
710 ls->ipv6only = 0;
711
712 } else {
713 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
714 "invalid ipv6only flags \"%s\"",
715 &value[i].data[9]);
716 return NGX_CONF_ERROR;
717 }
718
719 ls->bind = 1;
720 continue;
721 #else
722 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
723 "bind ipv6only is not supported "
724 "on this platform");
725 return NGX_CONF_ERROR;
726 #endif
727 }
728
729 if (ngx_strcmp(value[i].data, "reuseport") == 0) {
730 #if (NGX_HAVE_REUSEPORT)
731 ls->reuseport = 1;
732 ls->bind = 1;
733 #else
734 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
735 "reuseport is not supported "
736 "on this platform, ignored");
737 #endif
738 continue;
739 }
740
741 if (ngx_strcmp(value[i].data, "ssl") == 0) {
742 #if (NGX_STREAM_SSL)
743 ngx_stream_ssl_conf_t *sslcf;
744
745 sslcf = ngx_stream_conf_get_module_srv_conf(cf,
746 ngx_stream_ssl_module);
747
748 sslcf->listen = 1;
749 sslcf->file = cf->conf_file->file.name.data;
750 sslcf->line = cf->conf_file->line;
751
752 ls->ssl = 1;
753
754 continue;
755 #else
756 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
757 "the \"ssl\" parameter requires "
758 "ngx_stream_ssl_module");
759 return NGX_CONF_ERROR;
760 #endif
761 }
762
763 if (ngx_strncmp(value[i].data, "so_keepalive=", 13) == 0) {
764
765 if (ngx_strcmp(&value[i].data[13], "on") == 0) {
766 ls->so_keepalive = 1;
767
768 } else if (ngx_strcmp(&value[i].data[13], "off") == 0) {
769 ls->so_keepalive = 2;
770
771 } else {
772
773 #if (NGX_HAVE_KEEPALIVE_TUNABLE)
774 u_char *p, *end;
775 ngx_str_t s;
776
777 end = value[i].data + value[i].len;
778 s.data = value[i].data + 13;
779
780 p = ngx_strlchr(s.data, end, ':');
781 if (p == NULL) {
782 p = end;
783 }
784
785 if (p > s.data) {
786 s.len = p - s.data;
787
788 ls->tcp_keepidle = ngx_parse_time(&s, 1);
789 if (ls->tcp_keepidle == (time_t) NGX_ERROR) {
790 goto invalid_so_keepalive;
791 }
792 }
793
794 s.data = (p < end) ? (p + 1) : end;
795
796 p = ngx_strlchr(s.data, end, ':');
797 if (p == NULL) {
798 p = end;
799 }
800
801 if (p > s.data) {
802 s.len = p - s.data;
803
804 ls->tcp_keepintvl = ngx_parse_time(&s, 1);
805 if (ls->tcp_keepintvl == (time_t) NGX_ERROR) {
806 goto invalid_so_keepalive;
807 }
808 }
809
810 s.data = (p < end) ? (p + 1) : end;
811
812 if (s.data < end) {
813 s.len = end - s.data;
814
815 ls->tcp_keepcnt = ngx_atoi(s.data, s.len);
816 if (ls->tcp_keepcnt == NGX_ERROR) {
817 goto invalid_so_keepalive;
818 }
819 }
820
821 if (ls->tcp_keepidle == 0 && ls->tcp_keepintvl == 0
822 && ls->tcp_keepcnt == 0)
823 {
824 goto invalid_so_keepalive;
825 }
826
827 ls->so_keepalive = 1;
828
829 #else
830
831 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
832 "the \"so_keepalive\" parameter accepts "
833 "only \"on\" or \"off\" on this platform");
834 return NGX_CONF_ERROR;
835
836 #endif
837 }
838
839 ls->bind = 1;
840
841 continue;
842
843 #if (NGX_HAVE_KEEPALIVE_TUNABLE)
844 invalid_so_keepalive:
845
846 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
847 "invalid so_keepalive value: \"%s\"",
848 &value[i].data[13]);
849 return NGX_CONF_ERROR;
850 #endif
851 }
852
853 if (ngx_strcmp(value[i].data, "proxy_protocol") == 0) {
854 ls->proxy_protocol = 1;
855 continue;
856 }
857
858 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
859 "the invalid \"%V\" parameter", &value[i]);
860 return NGX_CONF_ERROR;
861 }
862
863 if (ls->type == SOCK_DGRAM) {
864 if (backlog) {
865 return "\"backlog\" parameter is incompatible with \"udp\"";
866 }
867
868 #if (NGX_STREAM_SSL)
869 if (ls->ssl) {
870 return "\"ssl\" parameter is incompatible with \"udp\"";
871 }
872 #endif
873
874 if (ls->so_keepalive) {
875 return "\"so_keepalive\" parameter is incompatible with \"udp\"";
876 }
877
878 if (ls->proxy_protocol) {
879 return "\"proxy_protocol\" parameter is incompatible with \"udp\"";
880 }
881 }
882
883 als = cmcf->listen.elts;
884
885 for (n = 0; n < u.naddrs; n++) {
886 ls[n] = ls[0];
887
888 ls[n].sockaddr = u.addrs[n].sockaddr;
889 ls[n].socklen = u.addrs[n].socklen;
890 ls[n].addr_text = u.addrs[n].name;
891 ls[n].wildcard = ngx_inet_wildcard(ls[n].sockaddr);
892
893 for (i = 0; i < cmcf->listen.nelts - u.naddrs + n; i++) {
894 if (ls[n].type != als[i].type) {
895 continue;
896 }
897
898 if (ngx_cmp_sockaddr(als[i].sockaddr, als[i].socklen,
899 ls[n].sockaddr, ls[n].socklen, 1)
900 != NGX_OK)
901 {
902 continue;
903 }
904
905 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
906 "duplicate \"%V\" address and port pair",
907 &ls[n].addr_text);
908 return NGX_CONF_ERROR;
909 }
910 }
911
912 return NGX_CONF_OK;
913 }
914
915
916 static char *
ngx_stream_core_resolver(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)917 ngx_stream_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
918 {
919 ngx_stream_core_srv_conf_t *cscf = conf;
920
921 ngx_str_t *value;
922
923 if (cscf->resolver) {
924 return "is duplicate";
925 }
926
927 value = cf->args->elts;
928
929 cscf->resolver = ngx_resolver_create(cf, &value[1], cf->args->nelts - 1);
930 if (cscf->resolver == NULL) {
931 return NGX_CONF_ERROR;
932 }
933
934 return NGX_CONF_OK;
935 }
936