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