source: nginx/src/core/ngx_connection.c

Last change on this file was 7119:fef61d26da39, checked in by Maxim Dounin <mdounin@…>, 5 months ago

Fixed buffer overread with unix sockets after accept().

Some OSes (notably macOS, NetBSD, and Solaris) allow unix socket addresses
larger than struct sockaddr_un. Moreover, some of them (macOS, Solaris)
return socklen of the socket address before it was truncated to fit the
buffer provided. As such, on these systems socklen must not be used without
additional check that it is within the buffer provided.

Appropriate checks added to ngx_event_accept() (after accept()),
ngx_event_recvmsg() (after recvmsg()), and ngx_set_inherited_sockets()
(after getsockname()).

We also obtain socket addresses via getsockname() in
ngx_connection_local_sockaddr(), but it does not need any checks as
it is only used for INET and INET6 sockets (as there can be no
wildcard unix sockets).

File size: 38.0 KB
Line 
1
2/*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8#include <ngx_config.h>
9#include <ngx_core.h>
10#include <ngx_event.h>
11
12
13ngx_os_io_t  ngx_io;
14
15
16static void ngx_drain_connections(ngx_cycle_t *cycle);
17
18
19ngx_listening_t *
20ngx_create_listening(ngx_conf_t *cf, struct sockaddr *sockaddr,
21    socklen_t socklen)
22{
23    size_t            len;
24    ngx_listening_t  *ls;
25    struct sockaddr  *sa;
26    u_char            text[NGX_SOCKADDR_STRLEN];
27
28    ls = ngx_array_push(&cf->cycle->listening);
29    if (ls == NULL) {
30        return NULL;
31    }
32
33    ngx_memzero(ls, sizeof(ngx_listening_t));
34
35    sa = ngx_palloc(cf->pool, socklen);
36    if (sa == NULL) {
37        return NULL;
38    }
39
40    ngx_memcpy(sa, sockaddr, socklen);
41
42    ls->sockaddr = sa;
43    ls->socklen = socklen;
44
45    len = ngx_sock_ntop(sa, socklen, text, NGX_SOCKADDR_STRLEN, 1);
46    ls->addr_text.len = len;
47
48    switch (ls->sockaddr->sa_family) {
49#if (NGX_HAVE_INET6)
50    case AF_INET6:
51        ls->addr_text_max_len = NGX_INET6_ADDRSTRLEN;
52        break;
53#endif
54#if (NGX_HAVE_UNIX_DOMAIN)
55    case AF_UNIX:
56        ls->addr_text_max_len = NGX_UNIX_ADDRSTRLEN;
57        len++;
58        break;
59#endif
60    case AF_INET:
61        ls->addr_text_max_len = NGX_INET_ADDRSTRLEN;
62        break;
63    default:
64        ls->addr_text_max_len = NGX_SOCKADDR_STRLEN;
65        break;
66    }
67
68    ls->addr_text.data = ngx_pnalloc(cf->pool, len);
69    if (ls->addr_text.data == NULL) {
70        return NULL;
71    }
72
73    ngx_memcpy(ls->addr_text.data, text, len);
74
75    ls->fd = (ngx_socket_t) -1;
76    ls->type = SOCK_STREAM;
77
78    ls->backlog = NGX_LISTEN_BACKLOG;
79    ls->rcvbuf = -1;
80    ls->sndbuf = -1;
81
82#if (NGX_HAVE_SETFIB)
83    ls->setfib = -1;
84#endif
85
86#if (NGX_HAVE_TCP_FASTOPEN)
87    ls->fastopen = -1;
88#endif
89
90    return ls;
91}
92
93
94ngx_int_t
95ngx_clone_listening(ngx_conf_t *cf, ngx_listening_t *ls)
96{
97#if (NGX_HAVE_REUSEPORT)
98
99    ngx_int_t         n;
100    ngx_core_conf_t  *ccf;
101    ngx_listening_t   ols;
102
103    if (!ls->reuseport) {
104        return NGX_OK;
105    }
106
107    ols = *ls;
108
109    ccf = (ngx_core_conf_t *) ngx_get_conf(cf->cycle->conf_ctx,
110                                           ngx_core_module);
111
112    for (n = 1; n < ccf->worker_processes; n++) {
113
114        /* create a socket for each worker process */
115
116        ls = ngx_array_push(&cf->cycle->listening);
117        if (ls == NULL) {
118            return NGX_ERROR;
119        }
120
121        *ls = ols;
122        ls->worker = n;
123    }
124
125#endif
126
127    return NGX_OK;
128}
129
130
131ngx_int_t
132ngx_set_inherited_sockets(ngx_cycle_t *cycle)
133{
134    size_t                     len;
135    ngx_uint_t                 i;
136    ngx_listening_t           *ls;
137    socklen_t                  olen;
138#if (NGX_HAVE_DEFERRED_ACCEPT || NGX_HAVE_TCP_FASTOPEN)
139    ngx_err_t                  err;
140#endif
141#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
142    struct accept_filter_arg   af;
143#endif
144#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
145    int                        timeout;
146#endif
147#if (NGX_HAVE_REUSEPORT)
148    int                        reuseport;
149#endif
150
151    ls = cycle->listening.elts;
152    for (i = 0; i < cycle->listening.nelts; i++) {
153
154        ls[i].sockaddr = ngx_palloc(cycle->pool, sizeof(ngx_sockaddr_t));
155        if (ls[i].sockaddr == NULL) {
156            return NGX_ERROR;
157        }
158
159        ls[i].socklen = sizeof(ngx_sockaddr_t);
160        if (getsockname(ls[i].fd, ls[i].sockaddr, &ls[i].socklen) == -1) {
161            ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,
162                          "getsockname() of the inherited "
163                          "socket #%d failed", ls[i].fd);
164            ls[i].ignore = 1;
165            continue;
166        }
167
168        if (ls[i].socklen > (socklen_t) sizeof(ngx_sockaddr_t)) {
169            ls[i].socklen = sizeof(ngx_sockaddr_t);
170        }
171
172        switch (ls[i].sockaddr->sa_family) {
173
174#if (NGX_HAVE_INET6)
175        case AF_INET6:
176            ls[i].addr_text_max_len = NGX_INET6_ADDRSTRLEN;
177            len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1;
178            break;
179#endif
180
181#if (NGX_HAVE_UNIX_DOMAIN)
182        case AF_UNIX:
183            ls[i].addr_text_max_len = NGX_UNIX_ADDRSTRLEN;
184            len = NGX_UNIX_ADDRSTRLEN;
185            break;
186#endif
187
188        case AF_INET:
189            ls[i].addr_text_max_len = NGX_INET_ADDRSTRLEN;
190            len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
191            break;
192
193        default:
194            ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,
195                          "the inherited socket #%d has "
196                          "an unsupported protocol family", ls[i].fd);
197            ls[i].ignore = 1;
198            continue;
199        }
200
201        ls[i].addr_text.data = ngx_pnalloc(cycle->pool, len);
202        if (ls[i].addr_text.data == NULL) {
203            return NGX_ERROR;
204        }
205
206        len = ngx_sock_ntop(ls[i].sockaddr, ls[i].socklen,
207                            ls[i].addr_text.data, len, 1);
208        if (len == 0) {
209            return NGX_ERROR;
210        }
211
212        ls[i].addr_text.len = len;
213
214        ls[i].backlog = NGX_LISTEN_BACKLOG;
215
216        olen = sizeof(int);
217
218        if (getsockopt(ls[i].fd, SOL_SOCKET, SO_TYPE, (void *) &ls[i].type,
219                       &olen)
220            == -1)
221        {
222            ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,
223                          "getsockopt(SO_TYPE) %V failed", &ls[i].addr_text);
224            ls[i].ignore = 1;
225            continue;
226        }
227
228        olen = sizeof(int);
229
230        if (getsockopt(ls[i].fd, SOL_SOCKET, SO_RCVBUF, (void *) &ls[i].rcvbuf,
231                       &olen)
232            == -1)
233        {
234            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
235                          "getsockopt(SO_RCVBUF) %V failed, ignored",
236                          &ls[i].addr_text);
237
238            ls[i].rcvbuf = -1;
239        }
240
241        olen = sizeof(int);
242
243        if (getsockopt(ls[i].fd, SOL_SOCKET, SO_SNDBUF, (void *) &ls[i].sndbuf,
244                       &olen)
245            == -1)
246        {
247            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
248                          "getsockopt(SO_SNDBUF) %V failed, ignored",
249                          &ls[i].addr_text);
250
251            ls[i].sndbuf = -1;
252        }
253
254#if 0
255        /* SO_SETFIB is currently a set only option */
256
257#if (NGX_HAVE_SETFIB)
258
259        olen = sizeof(int);
260
261        if (getsockopt(ls[i].fd, SOL_SOCKET, SO_SETFIB,
262                       (void *) &ls[i].setfib, &olen)
263            == -1)
264        {
265            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
266                          "getsockopt(SO_SETFIB) %V failed, ignored",
267                          &ls[i].addr_text);
268
269            ls[i].setfib = -1;
270        }
271
272#endif
273#endif
274
275#if (NGX_HAVE_REUSEPORT)
276
277        reuseport = 0;
278        olen = sizeof(int);
279
280        if (getsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT,
281                       (void *) &reuseport, &olen)
282            == -1)
283        {
284            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
285                          "getsockopt(SO_REUSEPORT) %V failed, ignored",
286                          &ls[i].addr_text);
287
288        } else {
289            ls[i].reuseport = reuseport ? 1 : 0;
290        }
291
292#endif
293
294        if (ls[i].type != SOCK_STREAM) {
295            continue;
296        }
297
298#if (NGX_HAVE_TCP_FASTOPEN)
299
300        olen = sizeof(int);
301
302        if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_FASTOPEN,
303                       (void *) &ls[i].fastopen, &olen)
304            == -1)
305        {
306            err = ngx_socket_errno;
307
308            if (err != NGX_EOPNOTSUPP && err != NGX_ENOPROTOOPT) {
309                ngx_log_error(NGX_LOG_NOTICE, cycle->log, err,
310                              "getsockopt(TCP_FASTOPEN) %V failed, ignored",
311                              &ls[i].addr_text);
312            }
313
314            ls[i].fastopen = -1;
315        }
316
317#endif
318
319#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
320
321        ngx_memzero(&af, sizeof(struct accept_filter_arg));
322        olen = sizeof(struct accept_filter_arg);
323
324        if (getsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, &af, &olen)
325            == -1)
326        {
327            err = ngx_socket_errno;
328
329            if (err == NGX_EINVAL) {
330                continue;
331            }
332
333            ngx_log_error(NGX_LOG_NOTICE, cycle->log, err,
334                          "getsockopt(SO_ACCEPTFILTER) for %V failed, ignored",
335                          &ls[i].addr_text);
336            continue;
337        }
338
339        if (olen < sizeof(struct accept_filter_arg) || af.af_name[0] == '\0') {
340            continue;
341        }
342
343        ls[i].accept_filter = ngx_palloc(cycle->pool, 16);
344        if (ls[i].accept_filter == NULL) {
345            return NGX_ERROR;
346        }
347
348        (void) ngx_cpystrn((u_char *) ls[i].accept_filter,
349                           (u_char *) af.af_name, 16);
350#endif
351
352#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
353
354        timeout = 0;
355        olen = sizeof(int);
356
357        if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, &olen)
358            == -1)
359        {
360            err = ngx_socket_errno;
361
362            if (err == NGX_EOPNOTSUPP) {
363                continue;
364            }
365
366            ngx_log_error(NGX_LOG_NOTICE, cycle->log, err,
367                          "getsockopt(TCP_DEFER_ACCEPT) for %V failed, ignored",
368                          &ls[i].addr_text);
369            continue;
370        }
371
372        if (olen < sizeof(int) || timeout == 0) {
373            continue;
374        }
375
376        ls[i].deferred_accept = 1;
377#endif
378    }
379
380    return NGX_OK;
381}
382
383
384ngx_int_t
385ngx_open_listening_sockets(ngx_cycle_t *cycle)
386{
387    int               reuseaddr;
388    ngx_uint_t        i, tries, failed;
389    ngx_err_t         err;
390    ngx_log_t        *log;
391    ngx_socket_t      s;
392    ngx_listening_t  *ls;
393
394    reuseaddr = 1;
395#if (NGX_SUPPRESS_WARN)
396    failed = 0;
397#endif
398
399    log = cycle->log;
400
401    /* TODO: configurable try number */
402
403    for (tries = 5; tries; tries--) {
404        failed = 0;
405
406        /* for each listening socket */
407
408        ls = cycle->listening.elts;
409        for (i = 0; i < cycle->listening.nelts; i++) {
410
411            if (ls[i].ignore) {
412                continue;
413            }
414
415#if (NGX_HAVE_REUSEPORT)
416
417            if (ls[i].add_reuseport) {
418
419                /*
420                 * to allow transition from a socket without SO_REUSEPORT
421                 * to multiple sockets with SO_REUSEPORT, we have to set
422                 * SO_REUSEPORT on the old socket before opening new ones
423                 */
424
425                int  reuseport = 1;
426
427                if (setsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT,
428                               (const void *) &reuseport, sizeof(int))
429                    == -1)
430                {
431                    ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
432                                  "setsockopt(SO_REUSEPORT) %V failed, ignored",
433                                  &ls[i].addr_text);
434                }
435
436                ls[i].add_reuseport = 0;
437            }
438#endif
439
440            if (ls[i].fd != (ngx_socket_t) -1) {
441                continue;
442            }
443
444            if (ls[i].inherited) {
445
446                /* TODO: close on exit */
447                /* TODO: nonblocking */
448                /* TODO: deferred accept */
449
450                continue;
451            }
452
453            s = ngx_socket(ls[i].sockaddr->sa_family, ls[i].type, 0);
454
455            if (s == (ngx_socket_t) -1) {
456                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
457                              ngx_socket_n " %V failed", &ls[i].addr_text);
458                return NGX_ERROR;
459            }
460
461            if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
462                           (const void *) &reuseaddr, sizeof(int))
463                == -1)
464            {
465                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
466                              "setsockopt(SO_REUSEADDR) %V failed",
467                              &ls[i].addr_text);
468
469                if (ngx_close_socket(s) == -1) {
470                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
471                                  ngx_close_socket_n " %V failed",
472                                  &ls[i].addr_text);
473                }
474
475                return NGX_ERROR;
476            }
477
478#if (NGX_HAVE_REUSEPORT)
479
480            if (ls[i].reuseport && !ngx_test_config) {
481                int  reuseport;
482
483                reuseport = 1;
484
485                if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT,
486                               (const void *) &reuseport, sizeof(int))
487                    == -1)
488                {
489                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
490                                  "setsockopt(SO_REUSEPORT) %V failed",
491                                  &ls[i].addr_text);
492
493                    if (ngx_close_socket(s) == -1) {
494                        ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
495                                      ngx_close_socket_n " %V failed",
496                                      &ls[i].addr_text);
497                    }
498
499                    return NGX_ERROR;
500                }
501            }
502#endif
503
504#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
505
506            if (ls[i].sockaddr->sa_family == AF_INET6) {
507                int  ipv6only;
508
509                ipv6only = ls[i].ipv6only;
510
511                if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
512                               (const void *) &ipv6only, sizeof(int))
513                    == -1)
514                {
515                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
516                                  "setsockopt(IPV6_V6ONLY) %V failed, ignored",
517                                  &ls[i].addr_text);
518                }
519            }
520#endif
521            /* TODO: close on exit */
522
523            if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) {
524                if (ngx_nonblocking(s) == -1) {
525                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
526                                  ngx_nonblocking_n " %V failed",
527                                  &ls[i].addr_text);
528
529                    if (ngx_close_socket(s) == -1) {
530                        ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
531                                      ngx_close_socket_n " %V failed",
532                                      &ls[i].addr_text);
533                    }
534
535                    return NGX_ERROR;
536                }
537            }
538
539            ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0,
540                           "bind() %V #%d ", &ls[i].addr_text, s);
541
542            if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) {
543                err = ngx_socket_errno;
544
545                if (err != NGX_EADDRINUSE || !ngx_test_config) {
546                    ngx_log_error(NGX_LOG_EMERG, log, err,
547                                  "bind() to %V failed", &ls[i].addr_text);
548                }
549
550                if (ngx_close_socket(s) == -1) {
551                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
552                                  ngx_close_socket_n " %V failed",
553                                  &ls[i].addr_text);
554                }
555
556                if (err != NGX_EADDRINUSE) {
557                    return NGX_ERROR;
558                }
559
560                if (!ngx_test_config) {
561                    failed = 1;
562                }
563
564                continue;
565            }
566
567#if (NGX_HAVE_UNIX_DOMAIN)
568
569            if (ls[i].sockaddr->sa_family == AF_UNIX) {
570                mode_t   mode;
571                u_char  *name;
572
573                name = ls[i].addr_text.data + sizeof("unix:") - 1;
574                mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
575
576                if (chmod((char *) name, mode) == -1) {
577                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
578                                  "chmod() \"%s\" failed", name);
579                }
580
581                if (ngx_test_config) {
582                    if (ngx_delete_file(name) == NGX_FILE_ERROR) {
583                        ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
584                                      ngx_delete_file_n " %s failed", name);
585                    }
586                }
587            }
588#endif
589
590            if (ls[i].type != SOCK_STREAM) {
591                ls[i].fd = s;
592                continue;
593            }
594
595            if (listen(s, ls[i].backlog) == -1) {
596                err = ngx_socket_errno;
597
598                /*
599                 * on OpenVZ after suspend/resume EADDRINUSE
600                 * may be returned by listen() instead of bind(), see
601                 * https://bugzilla.openvz.org/show_bug.cgi?id=2470
602                 */
603
604                if (err != NGX_EADDRINUSE || !ngx_test_config) {
605                    ngx_log_error(NGX_LOG_EMERG, log, err,
606                                  "listen() to %V, backlog %d failed",
607                                  &ls[i].addr_text, ls[i].backlog);
608                }
609
610                if (ngx_close_socket(s) == -1) {
611                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
612                                  ngx_close_socket_n " %V failed",
613                                  &ls[i].addr_text);
614                }
615
616                if (err != NGX_EADDRINUSE) {
617                    return NGX_ERROR;
618                }
619
620                if (!ngx_test_config) {
621                    failed = 1;
622                }
623
624                continue;
625            }
626
627            ls[i].listen = 1;
628
629            ls[i].fd = s;
630        }
631
632        if (!failed) {
633            break;
634        }
635
636        /* TODO: delay configurable */
637
638        ngx_log_error(NGX_LOG_NOTICE, log, 0,
639                      "try again to bind() after 500ms");
640
641        ngx_msleep(500);
642    }
643
644    if (failed) {
645        ngx_log_error(NGX_LOG_EMERG, log, 0, "still could not bind()");
646        return NGX_ERROR;
647    }
648
649    return NGX_OK;
650}
651
652
653void
654ngx_configure_listening_sockets(ngx_cycle_t *cycle)
655{
656    int                        value;
657    ngx_uint_t                 i;
658    ngx_listening_t           *ls;
659
660#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
661    struct accept_filter_arg   af;
662#endif
663
664    ls = cycle->listening.elts;
665    for (i = 0; i < cycle->listening.nelts; i++) {
666
667        ls[i].log = *ls[i].logp;
668
669        if (ls[i].rcvbuf != -1) {
670            if (setsockopt(ls[i].fd, SOL_SOCKET, SO_RCVBUF,
671                           (const void *) &ls[i].rcvbuf, sizeof(int))
672                == -1)
673            {
674                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
675                              "setsockopt(SO_RCVBUF, %d) %V failed, ignored",
676                              ls[i].rcvbuf, &ls[i].addr_text);
677            }
678        }
679
680        if (ls[i].sndbuf != -1) {
681            if (setsockopt(ls[i].fd, SOL_SOCKET, SO_SNDBUF,
682                           (const void *) &ls[i].sndbuf, sizeof(int))
683                == -1)
684            {
685                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
686                              "setsockopt(SO_SNDBUF, %d) %V failed, ignored",
687                              ls[i].sndbuf, &ls[i].addr_text);
688            }
689        }
690
691        if (ls[i].keepalive) {
692            value = (ls[i].keepalive == 1) ? 1 : 0;
693
694            if (setsockopt(ls[i].fd, SOL_SOCKET, SO_KEEPALIVE,
695                           (const void *) &value, sizeof(int))
696                == -1)
697            {
698                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
699                              "setsockopt(SO_KEEPALIVE, %d) %V failed, ignored",
700                              value, &ls[i].addr_text);
701            }
702        }
703
704#if (NGX_HAVE_KEEPALIVE_TUNABLE)
705
706        if (ls[i].keepidle) {
707            value = ls[i].keepidle;
708
709#if (NGX_KEEPALIVE_FACTOR)
710            value *= NGX_KEEPALIVE_FACTOR;
711#endif
712
713            if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPIDLE,
714                           (const void *) &value, sizeof(int))
715                == -1)
716            {
717                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
718                              "setsockopt(TCP_KEEPIDLE, %d) %V failed, ignored",
719                              value, &ls[i].addr_text);
720            }
721        }
722
723        if (ls[i].keepintvl) {
724            value = ls[i].keepintvl;
725
726#if (NGX_KEEPALIVE_FACTOR)
727            value *= NGX_KEEPALIVE_FACTOR;
728#endif
729
730            if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPINTVL,
731                           (const void *) &value, sizeof(int))
732                == -1)
733            {
734                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
735                             "setsockopt(TCP_KEEPINTVL, %d) %V failed, ignored",
736                             value, &ls[i].addr_text);
737            }
738        }
739
740        if (ls[i].keepcnt) {
741            if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPCNT,
742                           (const void *) &ls[i].keepcnt, sizeof(int))
743                == -1)
744            {
745                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
746                              "setsockopt(TCP_KEEPCNT, %d) %V failed, ignored",
747                              ls[i].keepcnt, &ls[i].addr_text);
748            }
749        }
750
751#endif
752
753#if (NGX_HAVE_SETFIB)
754        if (ls[i].setfib != -1) {
755            if (setsockopt(ls[i].fd, SOL_SOCKET, SO_SETFIB,
756                           (const void *) &ls[i].setfib, sizeof(int))
757                == -1)
758            {
759                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
760                              "setsockopt(SO_SETFIB, %d) %V failed, ignored",
761                              ls[i].setfib, &ls[i].addr_text);
762            }
763        }
764#endif
765
766#if (NGX_HAVE_TCP_FASTOPEN)
767        if (ls[i].fastopen != -1) {
768            if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_FASTOPEN,
769                           (const void *) &ls[i].fastopen, sizeof(int))
770                == -1)
771            {
772                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
773                              "setsockopt(TCP_FASTOPEN, %d) %V failed, ignored",
774                              ls[i].fastopen, &ls[i].addr_text);
775            }
776        }
777#endif
778
779#if 0
780        if (1) {
781            int tcp_nodelay = 1;
782
783            if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_NODELAY,
784                       (const void *) &tcp_nodelay, sizeof(int))
785                == -1)
786            {
787                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
788                              "setsockopt(TCP_NODELAY) %V failed, ignored",
789                              &ls[i].addr_text);
790            }
791        }
792#endif
793
794        if (ls[i].listen) {
795
796            /* change backlog via listen() */
797
798            if (listen(ls[i].fd, ls[i].backlog) == -1) {
799                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
800                              "listen() to %V, backlog %d failed, ignored",
801                              &ls[i].addr_text, ls[i].backlog);
802            }
803        }
804
805        /*
806         * setting deferred mode should be last operation on socket,
807         * because code may prematurely continue cycle on failure
808         */
809
810#if (NGX_HAVE_DEFERRED_ACCEPT)
811
812#ifdef SO_ACCEPTFILTER
813
814        if (ls[i].delete_deferred) {
815            if (setsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, NULL, 0)
816                == -1)
817            {
818                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
819                              "setsockopt(SO_ACCEPTFILTER, NULL) "
820                              "for %V failed, ignored",
821                              &ls[i].addr_text);
822
823                if (ls[i].accept_filter) {
824                    ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
825                                  "could not change the accept filter "
826                                  "to \"%s\" for %V, ignored",
827                                  ls[i].accept_filter, &ls[i].addr_text);
828                }
829
830                continue;
831            }
832
833            ls[i].deferred_accept = 0;
834        }
835
836        if (ls[i].add_deferred) {
837            ngx_memzero(&af, sizeof(struct accept_filter_arg));
838            (void) ngx_cpystrn((u_char *) af.af_name,
839                               (u_char *) ls[i].accept_filter, 16);
840
841            if (setsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER,
842                           &af, sizeof(struct accept_filter_arg))
843                == -1)
844            {
845                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
846                              "setsockopt(SO_ACCEPTFILTER, \"%s\") "
847                              "for %V failed, ignored",
848                              ls[i].accept_filter, &ls[i].addr_text);
849                continue;
850            }
851
852            ls[i].deferred_accept = 1;
853        }
854
855#endif
856
857#ifdef TCP_DEFER_ACCEPT
858
859        if (ls[i].add_deferred || ls[i].delete_deferred) {
860
861            if (ls[i].add_deferred) {
862                /*
863                 * There is no way to find out how long a connection was
864                 * in queue (and a connection may bypass deferred queue at all
865                 * if syncookies were used), hence we use 1 second timeout
866                 * here.
867                 */
868                value = 1;
869
870            } else {
871                value = 0;
872            }
873
874            if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT,
875                           &value, sizeof(int))
876                == -1)
877            {
878                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
879                              "setsockopt(TCP_DEFER_ACCEPT, %d) for %V failed, "
880                              "ignored",
881                              value, &ls[i].addr_text);
882
883                continue;
884            }
885        }
886
887        if (ls[i].add_deferred) {
888            ls[i].deferred_accept = 1;
889        }
890
891#endif
892
893#endif /* NGX_HAVE_DEFERRED_ACCEPT */
894
895#if (NGX_HAVE_IP_RECVDSTADDR)
896
897        if (ls[i].wildcard
898            && ls[i].type == SOCK_DGRAM
899            && ls[i].sockaddr->sa_family == AF_INET)
900        {
901            value = 1;
902
903            if (setsockopt(ls[i].fd, IPPROTO_IP, IP_RECVDSTADDR,
904                           (const void *) &value, sizeof(int))
905                == -1)
906            {
907                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
908                              "setsockopt(IP_RECVDSTADDR) "
909                              "for %V failed, ignored",
910                              &ls[i].addr_text);
911            }
912        }
913
914#elif (NGX_HAVE_IP_PKTINFO)
915
916        if (ls[i].wildcard
917            && ls[i].type == SOCK_DGRAM
918            && ls[i].sockaddr->sa_family == AF_INET)
919        {
920            value = 1;
921
922            if (setsockopt(ls[i].fd, IPPROTO_IP, IP_PKTINFO,
923                           (const void *) &value, sizeof(int))
924                == -1)
925            {
926                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
927                              "setsockopt(IP_PKTINFO) "
928                              "for %V failed, ignored",
929                              &ls[i].addr_text);
930            }
931        }
932
933#endif
934
935#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
936
937        if (ls[i].wildcard
938            && ls[i].type == SOCK_DGRAM
939            && ls[i].sockaddr->sa_family == AF_INET6)
940        {
941            value = 1;
942
943            if (setsockopt(ls[i].fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
944                           (const void *) &value, sizeof(int))
945                == -1)
946            {
947                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
948                              "setsockopt(IPV6_RECVPKTINFO) "
949                              "for %V failed, ignored",
950                              &ls[i].addr_text);
951            }
952        }
953
954#endif
955    }
956
957    return;
958}
959
960
961void
962ngx_close_listening_sockets(ngx_cycle_t *cycle)
963{
964    ngx_uint_t         i;
965    ngx_listening_t   *ls;
966    ngx_connection_t  *c;
967
968    if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
969        return;
970    }
971
972    ngx_accept_mutex_held = 0;
973    ngx_use_accept_mutex = 0;
974
975    ls = cycle->listening.elts;
976    for (i = 0; i < cycle->listening.nelts; i++) {
977
978        c = ls[i].connection;
979
980        if (c) {
981            if (c->read->active) {
982                if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
983
984                    /*
985                     * it seems that Linux-2.6.x OpenVZ sends events
986                     * for closed shared listening sockets unless
987                     * the events was explicitly deleted
988                     */
989
990                    ngx_del_event(c->read, NGX_READ_EVENT, 0);
991
992                } else {
993                    ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
994                }
995            }
996
997            ngx_free_connection(c);
998
999            c->fd = (ngx_socket_t) -1;
1000        }
1001
1002        ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
1003                       "close listening %V #%d ", &ls[i].addr_text, ls[i].fd);
1004
1005        if (ngx_close_socket(ls[i].fd) == -1) {
1006            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
1007                          ngx_close_socket_n " %V failed", &ls[i].addr_text);
1008        }
1009
1010#if (NGX_HAVE_UNIX_DOMAIN)
1011
1012        if (ls[i].sockaddr->sa_family == AF_UNIX
1013            && ngx_process <= NGX_PROCESS_MASTER
1014            && ngx_new_binary == 0)
1015        {
1016            u_char *name = ls[i].addr_text.data + sizeof("unix:") - 1;
1017
1018            if (ngx_delete_file(name) == NGX_FILE_ERROR) {
1019                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
1020                              ngx_delete_file_n " %s failed", name);
1021            }
1022        }
1023
1024#endif
1025
1026        ls[i].fd = (ngx_socket_t) -1;
1027    }
1028
1029    cycle->listening.nelts = 0;
1030}
1031
1032
1033ngx_connection_t *
1034ngx_get_connection(ngx_socket_t s, ngx_log_t *log)
1035{
1036    ngx_uint_t         instance;
1037    ngx_event_t       *rev, *wev;
1038    ngx_connection_t  *c;
1039
1040    /* disable warning: Win32 SOCKET is u_int while UNIX socket is int */
1041
1042    if (ngx_cycle->files && (ngx_uint_t) s >= ngx_cycle->files_n) {
1043        ngx_log_error(NGX_LOG_ALERT, log, 0,
1044                      "the new socket has number %d, "
1045                      "but only %ui files are available",
1046                      s, ngx_cycle->files_n);
1047        return NULL;
1048    }
1049
1050    c = ngx_cycle->free_connections;
1051
1052    if (c == NULL) {
1053        ngx_drain_connections((ngx_cycle_t *) ngx_cycle);
1054        c = ngx_cycle->free_connections;
1055    }
1056
1057    if (c == NULL) {
1058        ngx_log_error(NGX_LOG_ALERT, log, 0,
1059                      "%ui worker_connections are not enough",
1060                      ngx_cycle->connection_n);
1061
1062        return NULL;
1063    }
1064
1065    ngx_cycle->free_connections = c->data;
1066    ngx_cycle->free_connection_n--;
1067
1068    if (ngx_cycle->files && ngx_cycle->files[s] == NULL) {
1069        ngx_cycle->files[s] = c;
1070    }
1071
1072    rev = c->read;
1073    wev = c->write;
1074
1075    ngx_memzero(c, sizeof(ngx_connection_t));
1076
1077    c->read = rev;
1078    c->write = wev;
1079    c->fd = s;
1080    c->log = log;
1081
1082    instance = rev->instance;
1083
1084    ngx_memzero(rev, sizeof(ngx_event_t));
1085    ngx_memzero(wev, sizeof(ngx_event_t));
1086
1087    rev->instance = !instance;
1088    wev->instance = !instance;
1089
1090    rev->index = NGX_INVALID_INDEX;
1091    wev->index = NGX_INVALID_INDEX;
1092
1093    rev->data = c;
1094    wev->data = c;
1095
1096    wev->write = 1;
1097
1098    return c;
1099}
1100
1101
1102void
1103ngx_free_connection(ngx_connection_t *c)
1104{
1105    c->data = ngx_cycle->free_connections;
1106    ngx_cycle->free_connections = c;
1107    ngx_cycle->free_connection_n++;
1108
1109    if (ngx_cycle->files && ngx_cycle->files[c->fd] == c) {
1110        ngx_cycle->files[c->fd] = NULL;
1111    }
1112}
1113
1114
1115void
1116ngx_close_connection(ngx_connection_t *c)
1117{
1118    ngx_err_t     err;
1119    ngx_uint_t    log_error, level;
1120    ngx_socket_t  fd;
1121
1122    if (c->fd == (ngx_socket_t) -1) {
1123        ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed");
1124        return;
1125    }
1126
1127    if (c->read->timer_set) {
1128        ngx_del_timer(c->read);
1129    }
1130
1131    if (c->write->timer_set) {
1132        ngx_del_timer(c->write);
1133    }
1134
1135    if (!c->shared) {
1136        if (ngx_del_conn) {
1137            ngx_del_conn(c, NGX_CLOSE_EVENT);
1138
1139        } else {
1140            if (c->read->active || c->read->disabled) {
1141                ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
1142            }
1143
1144            if (c->write->active || c->write->disabled) {
1145                ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT);
1146            }
1147        }
1148    }
1149
1150    if (c->read->posted) {
1151        ngx_delete_posted_event(c->read);
1152    }
1153
1154    if (c->write->posted) {
1155        ngx_delete_posted_event(c->write);
1156    }
1157
1158    c->read->closed = 1;
1159    c->write->closed = 1;
1160
1161    ngx_reusable_connection(c, 0);
1162
1163    log_error = c->log_error;
1164
1165    ngx_free_connection(c);
1166
1167    fd = c->fd;
1168    c->fd = (ngx_socket_t) -1;
1169
1170    if (c->shared) {
1171        return;
1172    }
1173
1174    if (ngx_close_socket(fd) == -1) {
1175
1176        err = ngx_socket_errno;
1177
1178        if (err == NGX_ECONNRESET || err == NGX_ENOTCONN) {
1179
1180            switch (log_error) {
1181
1182            case NGX_ERROR_INFO:
1183                level = NGX_LOG_INFO;
1184                break;
1185
1186            case NGX_ERROR_ERR:
1187                level = NGX_LOG_ERR;
1188                break;
1189
1190            default:
1191                level = NGX_LOG_CRIT;
1192            }
1193
1194        } else {
1195            level = NGX_LOG_CRIT;
1196        }
1197
1198        ngx_log_error(level, c->log, err, ngx_close_socket_n " %d failed", fd);
1199    }
1200}
1201
1202
1203void
1204ngx_reusable_connection(ngx_connection_t *c, ngx_uint_t reusable)
1205{
1206    ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
1207                   "reusable connection: %ui", reusable);
1208
1209    if (c->reusable) {
1210        ngx_queue_remove(&c->queue);
1211        ngx_cycle->reusable_connections_n--;
1212
1213#if (NGX_STAT_STUB)
1214        (void) ngx_atomic_fetch_add(ngx_stat_waiting, -1);
1215#endif
1216    }
1217
1218    c->reusable = reusable;
1219
1220    if (reusable) {
1221        /* need cast as ngx_cycle is volatile */
1222
1223        ngx_queue_insert_head(
1224            (ngx_queue_t *) &ngx_cycle->reusable_connections_queue, &c->queue);
1225        ngx_cycle->reusable_connections_n++;
1226
1227#if (NGX_STAT_STUB)
1228        (void) ngx_atomic_fetch_add(ngx_stat_waiting, 1);
1229#endif
1230    }
1231}
1232
1233
1234static void
1235ngx_drain_connections(ngx_cycle_t *cycle)
1236{
1237    ngx_uint_t         i, n;
1238    ngx_queue_t       *q;
1239    ngx_connection_t  *c;
1240
1241    n = ngx_max(ngx_min(32, cycle->reusable_connections_n / 8), 1);
1242
1243    for (i = 0; i < n; i++) {
1244        if (ngx_queue_empty(&cycle->reusable_connections_queue)) {
1245            break;
1246        }
1247
1248        q = ngx_queue_last(&cycle->reusable_connections_queue);
1249        c = ngx_queue_data(q, ngx_connection_t, queue);
1250
1251        ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0,
1252                       "reusing connection");
1253
1254        c->close = 1;
1255        c->read->handler(c->read);
1256    }
1257}
1258
1259
1260void
1261ngx_close_idle_connections(ngx_cycle_t *cycle)
1262{
1263    ngx_uint_t         i;
1264    ngx_connection_t  *c;
1265
1266    c = cycle->connections;
1267
1268    for (i = 0; i < cycle->connection_n; i++) {
1269
1270        /* THREAD: lock */
1271
1272        if (c[i].fd != (ngx_socket_t) -1 && c[i].idle) {
1273            c[i].close = 1;
1274            c[i].read->handler(c[i].read);
1275        }
1276    }
1277}
1278
1279
1280ngx_int_t
1281ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s,
1282    ngx_uint_t port)
1283{
1284    socklen_t             len;
1285    ngx_uint_t            addr;
1286    ngx_sockaddr_t        sa;
1287    struct sockaddr_in   *sin;
1288#if (NGX_HAVE_INET6)
1289    ngx_uint_t            i;
1290    struct sockaddr_in6  *sin6;
1291#endif
1292
1293    addr = 0;
1294
1295    if (c->local_socklen) {
1296        switch (c->local_sockaddr->sa_family) {
1297
1298#if (NGX_HAVE_INET6)
1299        case AF_INET6:
1300            sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
1301
1302            for (i = 0; addr == 0 && i < 16; i++) {
1303                addr |= sin6->sin6_addr.s6_addr[i];
1304            }
1305
1306            break;
1307#endif
1308
1309#if (NGX_HAVE_UNIX_DOMAIN)
1310        case AF_UNIX:
1311            addr = 1;
1312            break;
1313#endif
1314
1315        default: /* AF_INET */
1316            sin = (struct sockaddr_in *) c->local_sockaddr;
1317            addr = sin->sin_addr.s_addr;
1318            break;
1319        }
1320    }
1321
1322    if (addr == 0) {
1323
1324        len = sizeof(ngx_sockaddr_t);
1325
1326        if (getsockname(c->fd, &sa.sockaddr, &len) == -1) {
1327            ngx_connection_error(c, ngx_socket_errno, "getsockname() failed");
1328            return NGX_ERROR;
1329        }
1330
1331        c->local_sockaddr = ngx_palloc(c->pool, len);
1332        if (c->local_sockaddr == NULL) {
1333            return NGX_ERROR;
1334        }
1335
1336        ngx_memcpy(c->local_sockaddr, &sa, len);
1337
1338        c->local_socklen = len;
1339    }
1340
1341    if (s == NULL) {
1342        return NGX_OK;
1343    }
1344
1345    s->len = ngx_sock_ntop(c->local_sockaddr, c->local_socklen,
1346                           s->data, s->len, port);
1347
1348    return NGX_OK;
1349}
1350
1351
1352ngx_int_t
1353ngx_tcp_nodelay(ngx_connection_t *c)
1354{
1355    int  tcp_nodelay;
1356
1357    if (c->tcp_nodelay != NGX_TCP_NODELAY_UNSET) {
1358        return NGX_OK;
1359    }
1360
1361    ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0, "tcp_nodelay");
1362
1363    tcp_nodelay = 1;
1364
1365    if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
1366                   (const void *) &tcp_nodelay, sizeof(int))
1367        == -1)
1368    {
1369#if (NGX_SOLARIS)
1370        if (c->log_error == NGX_ERROR_INFO) {
1371
1372            /* Solaris returns EINVAL if a socket has been shut down */
1373            c->log_error = NGX_ERROR_IGNORE_EINVAL;
1374
1375            ngx_connection_error(c, ngx_socket_errno,
1376                                 "setsockopt(TCP_NODELAY) failed");
1377
1378            c->log_error = NGX_ERROR_INFO;
1379
1380            return NGX_ERROR;
1381        }
1382#endif
1383
1384        ngx_connection_error(c, ngx_socket_errno,
1385                             "setsockopt(TCP_NODELAY) failed");
1386        return NGX_ERROR;
1387    }
1388
1389    c->tcp_nodelay = NGX_TCP_NODELAY_SET;
1390
1391    return NGX_OK;
1392}
1393
1394
1395ngx_int_t
1396ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text)
1397{
1398    ngx_uint_t  level;
1399
1400    /* Winsock may return NGX_ECONNABORTED instead of NGX_ECONNRESET */
1401
1402    if ((err == NGX_ECONNRESET
1403#if (NGX_WIN32)
1404         || err == NGX_ECONNABORTED
1405#endif
1406        ) && c->log_error == NGX_ERROR_IGNORE_ECONNRESET)
1407    {
1408        return 0;
1409    }
1410
1411#if (NGX_SOLARIS)
1412    if (err == NGX_EINVAL && c->log_error == NGX_ERROR_IGNORE_EINVAL) {
1413        return 0;
1414    }
1415#endif
1416
1417    if (err == 0
1418        || err == NGX_ECONNRESET
1419#if (NGX_WIN32)
1420        || err == NGX_ECONNABORTED
1421#else
1422        || err == NGX_EPIPE
1423#endif
1424        || err == NGX_ENOTCONN
1425        || err == NGX_ETIMEDOUT
1426        || err == NGX_ECONNREFUSED
1427        || err == NGX_ENETDOWN
1428        || err == NGX_ENETUNREACH
1429        || err == NGX_EHOSTDOWN
1430        || err == NGX_EHOSTUNREACH)
1431    {
1432        switch (c->log_error) {
1433
1434        case NGX_ERROR_IGNORE_EINVAL:
1435        case NGX_ERROR_IGNORE_ECONNRESET:
1436        case NGX_ERROR_INFO:
1437            level = NGX_LOG_INFO;
1438            break;
1439
1440        default:
1441            level = NGX_LOG_ERR;
1442        }
1443
1444    } else {
1445        level = NGX_LOG_ALERT;
1446    }
1447
1448    ngx_log_error(level, c->log, err, text);
1449
1450    return NGX_ERROR;
1451}
Note: See TracBrowser for help on using the repository browser.