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