1 /*
2 * nghttp2 - HTTP/2 C Library
3 *
4 * Copyright (c) 2014 Tatsuhiro Tsujikawa
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25 #include "shrpx_accept_handler.h"
26
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif // HAVE_UNISTD_H
30
31 #include <cerrno>
32
33 #include "shrpx_connection_handler.h"
34 #include "shrpx_config.h"
35 #include "shrpx_log.h"
36 #include "util.h"
37
38 using namespace nghttp2;
39
40 namespace shrpx {
41
42 namespace {
acceptcb(struct ev_loop * loop,ev_io * w,int revent)43 void acceptcb(struct ev_loop *loop, ev_io *w, int revent) {
44 auto h = static_cast<AcceptHandler *>(w->data);
45 h->accept_connection();
46 }
47 } // namespace
48
AcceptHandler(const UpstreamAddr * faddr,ConnectionHandler * h)49 AcceptHandler::AcceptHandler(const UpstreamAddr *faddr, ConnectionHandler *h)
50 : conn_hnr_(h), faddr_(faddr) {
51 ev_io_init(&wev_, acceptcb, faddr_->fd, EV_READ);
52 wev_.data = this;
53 ev_io_start(conn_hnr_->get_loop(), &wev_);
54 }
55
~AcceptHandler()56 AcceptHandler::~AcceptHandler() {
57 ev_io_stop(conn_hnr_->get_loop(), &wev_);
58 close(faddr_->fd);
59 }
60
accept_connection()61 void AcceptHandler::accept_connection() {
62 sockaddr_union sockaddr;
63 socklen_t addrlen = sizeof(sockaddr);
64
65 #ifdef HAVE_ACCEPT4
66 auto cfd =
67 accept4(faddr_->fd, &sockaddr.sa, &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
68 #else // !HAVE_ACCEPT4
69 auto cfd = accept(faddr_->fd, &sockaddr.sa, &addrlen);
70 #endif // !HAVE_ACCEPT4
71
72 if (cfd == -1) {
73 switch (errno) {
74 case EINTR:
75 case ENETDOWN:
76 case EPROTO:
77 case ENOPROTOOPT:
78 case EHOSTDOWN:
79 #ifdef ENONET
80 case ENONET:
81 #endif // ENONET
82 case EHOSTUNREACH:
83 case EOPNOTSUPP:
84 case ENETUNREACH:
85 return;
86 case EMFILE:
87 case ENFILE:
88 LOG(WARN) << "acceptor: running out file descriptor; disable acceptor "
89 "temporarily";
90 conn_hnr_->sleep_acceptor(get_config()->conn.listener.timeout.sleep);
91 return;
92 default:
93 return;
94 }
95 }
96
97 #ifndef HAVE_ACCEPT4
98 util::make_socket_nonblocking(cfd);
99 util::make_socket_closeonexec(cfd);
100 #endif // !HAVE_ACCEPT4
101
102 conn_hnr_->handle_connection(cfd, &sockaddr.sa, addrlen, faddr_);
103 }
104
enable()105 void AcceptHandler::enable() { ev_io_start(conn_hnr_->get_loop(), &wev_); }
106
disable()107 void AcceptHandler::disable() { ev_io_stop(conn_hnr_->get_loop(), &wev_); }
108
get_fd() const109 int AcceptHandler::get_fd() const { return faddr_->fd; }
110
111 } // namespace shrpx
112